diff options
author | 2025-06-05 14:25:23 +0000 | |
---|---|---|
committer | 2025-06-05 14:25:23 +0000 | |
commit | e586d7d704d475afe3373a1de6ae20d504f79d6d (patch) | |
tree | 7e3fa24807cebd48a86bd40f866d792181191ee9 /packages/integrations/vue/test | |
download | astro-latest.tar.gz astro-latest.tar.zst astro-latest.zip |
Sync from a8e1c0a7402940e0fc5beef669522b315052df1blatest
Diffstat (limited to 'packages/integrations/vue/test')
60 files changed, 831 insertions, 0 deletions
diff --git a/packages/integrations/vue/test/app-entrypoint-css.test.js b/packages/integrations/vue/test/app-entrypoint-css.test.js new file mode 100644 index 000000000..878aa8e48 --- /dev/null +++ b/packages/integrations/vue/test/app-entrypoint-css.test.js @@ -0,0 +1,67 @@ +import * as assert from 'node:assert/strict'; +import { after, before, describe, it } from 'node:test'; +import { load as cheerioLoad } from 'cheerio'; +import { loadFixture } from './test-utils.js'; + +describe('App Entrypoint CSS', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/app-entrypoint-css/', + }); + }); + + describe('build', () => { + before(async () => { + await fixture.build(); + }); + + it('injects styles referenced in appEntrypoint', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerioLoad(html); + + // test 1: basic component renders + assert.equal($('#foo > #bar').text(), 'works'); + // test 2: injects the global style on the page + assert.equal($('style').first().text().trim(), ':root{background-color:red}'); + }); + + it('does not inject styles to pages without a Vue component', async () => { + const html = await fixture.readFile('/unrelated/index.html'); + const $ = cheerioLoad(html); + + assert.equal($('style').length, 0); + assert.equal($('link[rel="stylesheet"]').length, 0); + }); + }); + + describe('dev', () => { + let devServer; + before(async () => { + devServer = await fixture.startDevServer(); + }); + after(async () => { + await devServer.stop(); + }); + + it('loads during SSR', async () => { + const html = await fixture.fetch('/').then((res) => res.text()); + const $ = cheerioLoad(html); + + // test 1: basic component renders + assert.equal($('#foo > #bar').text(), 'works'); + // test 2: injects the global style on the page + assert.equal($('style').first().text().replace(/\s+/g, ''), ':root{background-color:red;}'); + }); + + it('does not inject styles to pages without a Vue component', async () => { + const html = await fixture.fetch('/unrelated').then((res) => res.text()); + const $ = cheerioLoad(html); + + assert.equal($('style').length, 0); + assert.equal($('link[rel="stylesheet"]').length, 0); + }); + }); +}); diff --git a/packages/integrations/vue/test/app-entrypoint.test.js b/packages/integrations/vue/test/app-entrypoint.test.js new file mode 100644 index 000000000..c7fa82826 --- /dev/null +++ b/packages/integrations/vue/test/app-entrypoint.test.js @@ -0,0 +1,210 @@ +import * as assert from 'node:assert/strict'; +import { after, before, describe, it } from 'node:test'; +import { load as cheerioLoad } from 'cheerio'; +import { parseHTML } from 'linkedom'; +import { loadFixture } from './test-utils.js'; + +describe('App Entrypoint', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/app-entrypoint/', + }); + await fixture.build(); + }); + + it('loads during SSR', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerioLoad(html); + + // test 1: basic component renders + assert.equal($('#foo > #bar').text(), 'works'); + + // test 2: component with multiple script blocks renders and exports + // values from non setup block correctly + assert.equal($('#multiple-script-blocks').text(), '2 4'); + + // test 3: component using generics renders + assert.equal($('#generics').text(), 'generic'); + + // test 4: component using generics and multiple script blocks renders + assert.equal($('#generics-and-blocks').text(), '1 3!!!'); + }); + + it('setup included in renderer bundle', async () => { + const data = await fixture.readFile('/index.html'); + const { document } = parseHTML(data); + const island = document.querySelector('astro-island'); + const client = island.getAttribute('renderer-url'); + assert.notEqual(client, undefined); + + const js = await fixture.readFile(client); + assert.match(js, /\w+\.component\("Bar"/g); + }); + + it('loads svg components without transforming them to assets', async () => { + const data = await fixture.readFile('/index.html'); + const { document } = parseHTML(data); + const client = document.querySelector('astro-island svg'); + + assert.notEqual(client, undefined); + }); +}); + +describe('App Entrypoint no export default (dev)', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + let devServer; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/app-entrypoint-no-export-default/', + }); + devServer = await fixture.startDevServer(); + }); + + after(async () => { + await devServer.stop(); + }); + + it('loads during SSR', async () => { + const html = await fixture.fetch('/').then((res) => res.text()); + const { document } = parseHTML(html); + const bar = document.querySelector('#foo > #bar'); + assert.notEqual(bar, undefined); + assert.equal(bar.textContent, 'works'); + }); + + it('loads svg components without transforming them to assets', async () => { + const html = await fixture.fetch('/').then((res) => res.text()); + const { document } = parseHTML(html); + const client = document.querySelector('astro-island svg'); + + assert.notEqual(client, undefined); + }); +}); + +describe('App Entrypoint no export default', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/app-entrypoint-no-export-default/', + }); + await fixture.build(); + }); + + it('loads during SSR', async () => { + const data = await fixture.readFile('/index.html'); + const { document } = parseHTML(data); + const bar = document.querySelector('#foo > #bar'); + assert.notEqual(bar, undefined); + assert.equal(bar.textContent, 'works'); + }); + + it('component not included in renderer bundle', async () => { + const data = await fixture.readFile('/index.html'); + const { document } = parseHTML(data); + const island = document.querySelector('astro-island'); + const client = island.getAttribute('renderer-url'); + assert.notEqual(client, undefined); + const js = await fixture.readFile(client); + assert.doesNotMatch(js, /\w+\.component\("Bar"/g); + }); + + it('loads svg components without transforming them to assets', async () => { + const data = await fixture.readFile('/index.html'); + const { document } = parseHTML(data); + const client = document.querySelector('astro-island svg'); + + assert.notEqual(client, undefined); + }); +}); + +describe('App Entrypoint relative', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/app-entrypoint-relative/', + }); + await fixture.build(); + }); + + it('loads during SSR', async () => { + const data = await fixture.readFile('/index.html'); + const { document } = parseHTML(data); + const bar = document.querySelector('#foo > #bar'); + assert.notEqual(bar, undefined); + assert.equal(bar.textContent, 'works'); + }); + + it('component not included in renderer bundle', async () => { + const data = await fixture.readFile('/index.html'); + const { document } = parseHTML(data); + const island = document.querySelector('astro-island'); + const client = island.getAttribute('renderer-url'); + assert.notEqual(client, undefined); + + const js = await fixture.readFile(client); + assert.doesNotMatch(js, /\w+\.component\("Bar"/g); + }); +}); + +describe('App Entrypoint /src/absolute', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/app-entrypoint-src-absolute/', + }); + await fixture.build(); + }); + + it('loads during SSR', async () => { + const data = await fixture.readFile('/index.html'); + const { document } = parseHTML(data); + const bar = document.querySelector('#foo > #bar'); + assert.notEqual(bar, undefined); + assert.equal(bar.textContent, 'works'); + }); + + it('component not included in renderer bundle', async () => { + const data = await fixture.readFile('/index.html'); + const { document } = parseHTML(data); + const island = document.querySelector('astro-island'); + const client = island.getAttribute('renderer-url'); + assert.notEqual(client, undefined); + + const js = await fixture.readFile(client); + assert.doesNotMatch(js, /\w+\.component\("Bar"/g); + }); +}); + +describe('App Entrypoint async', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/app-entrypoint-async/', + }); + await fixture.build(); + }); + + it('loads during SSR', async () => { + const html = await fixture.readFile('/index.html'); + const $ = cheerioLoad(html); + + // test 1: component before await renders + assert.equal($('#foo > #bar').text(), 'works'); + + // test 2: component after await renders + assert.equal($('#foo > #baz').text(), 'works'); + }); +}); diff --git a/packages/integrations/vue/test/basics.test.js b/packages/integrations/vue/test/basics.test.js new file mode 100644 index 000000000..d54ea66b6 --- /dev/null +++ b/packages/integrations/vue/test/basics.test.js @@ -0,0 +1,42 @@ +import * as assert from 'node:assert/strict'; +import { before, describe, it } from 'node:test'; +import { parseHTML } from 'linkedom'; +import { loadFixture } from './test-utils.js'; +describe('Basics', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/basics/', + }); + await fixture.build(); + }); + + it('Slots are added without the slot attribute', async () => { + const data = await fixture.readFile('/index.html'); + const { document } = parseHTML(data); + const bar = document.querySelector('#foo'); + + assert.notEqual(bar, undefined); + assert.equal(bar.getAttribute('slot'), null); + }); + + it('Can show images from public', async () => { + const data = await fixture.readFile('/public/index.html'); + const { document } = parseHTML(data); + const img = document.querySelector('img'); + + assert.notEqual(img, undefined); + assert.equal(img.getAttribute('src'), '/light_walrus.avif'); + }); + + it('Should generate unique ids when using useId()', async () => { + const data = await fixture.readFile('/index.html'); + const { document } = parseHTML(data); + + const els = document.querySelectorAll('.vue-use-id'); + assert.equal(els.length, 2); + assert.notEqual(els[0].getAttribute('id'), els[1].getAttribute('id')); + }); +}); diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-async/astro.config.mjs b/packages/integrations/vue/test/fixtures/app-entrypoint-async/astro.config.mjs new file mode 100644 index 000000000..e82b7310f --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-async/astro.config.mjs @@ -0,0 +1,14 @@ +import vue from '@astrojs/vue'; +import { defineConfig } from 'astro/config'; +import ViteSvgLoader from 'vite-svg-loader' + +export default defineConfig({ + integrations: [vue({ + appEntrypoint: '/src/pages/_app' + })], + vite: { + plugins: [ + ViteSvgLoader(), + ], + }, +}) diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-async/package.json b/packages/integrations/vue/test/fixtures/app-entrypoint-async/package.json new file mode 100644 index 000000000..abf571dc9 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-async/package.json @@ -0,0 +1,11 @@ +{ + "name": "@test/vue-app-entrypoint-async", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/vue": "workspace:*", + "astro": "workspace:*", + "vite-svg-loader": "5.1.0", + "vue": "^3.5.16" + } +}
\ No newline at end of file diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-async/src/components/Bar.vue b/packages/integrations/vue/test/fixtures/app-entrypoint-async/src/components/Bar.vue new file mode 100644 index 000000000..9e690ea06 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-async/src/components/Bar.vue @@ -0,0 +1,3 @@ +<template> + <div id="bar">works</div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-async/src/components/Baz.vue b/packages/integrations/vue/test/fixtures/app-entrypoint-async/src/components/Baz.vue new file mode 100644 index 000000000..8d7cb6b7c --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-async/src/components/Baz.vue @@ -0,0 +1,3 @@ +<template> + <div id="baz">works</div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-async/src/components/Foo.vue b/packages/integrations/vue/test/fixtures/app-entrypoint-async/src/components/Foo.vue new file mode 100644 index 000000000..94dd36584 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-async/src/components/Foo.vue @@ -0,0 +1,6 @@ +<template> + <div id="foo"> + <Bar /> + <Baz /> + </div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-async/src/pages/_app.ts b/packages/integrations/vue/test/fixtures/app-entrypoint-async/src/pages/_app.ts new file mode 100644 index 000000000..d2bc5396a --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-async/src/pages/_app.ts @@ -0,0 +1,11 @@ +import type { App } from 'vue' +import Bar from '../components/Bar.vue' +import Baz from '../components/Baz.vue' + +export default async function setup(app: App) { + app.component('Bar', Bar); + + await new Promise(resolve => setTimeout(resolve, 250)); + + app.component('Baz', Baz); +} diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-async/src/pages/index.astro b/packages/integrations/vue/test/fixtures/app-entrypoint-async/src/pages/index.astro new file mode 100644 index 000000000..3240cbe0f --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-async/src/pages/index.astro @@ -0,0 +1,12 @@ +--- +import Foo from '../components/Foo.vue'; +--- + +<html> + <head> + <title>Vue App Entrypoint</title> + </head> + <body> + <Foo client:load /> + </body> +</html> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-css/astro.config.mjs b/packages/integrations/vue/test/fixtures/app-entrypoint-css/astro.config.mjs new file mode 100644 index 000000000..cfc52edc8 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-css/astro.config.mjs @@ -0,0 +1,8 @@ +import vue from '@astrojs/vue'; +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + integrations: [ + vue({ appEntrypoint: '/src/app.ts' }) + ], +}) diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-css/package.json b/packages/integrations/vue/test/fixtures/app-entrypoint-css/package.json new file mode 100644 index 000000000..b34b4b99c --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-css/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/vue-app-entrypoint-css", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/vue": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/app.ts b/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/app.ts new file mode 100644 index 000000000..3f8025bb9 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/app.ts @@ -0,0 +1,9 @@ +import type { App } from 'vue' +// Important! Test that styles here are injected to the page +import '/src/main.css' +import Bar from './components/Bar.vue' + + +export default function setup(app: App) { + app.component('Bar', Bar); +} diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/components/Bar.vue b/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/components/Bar.vue new file mode 100644 index 000000000..9e690ea06 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/components/Bar.vue @@ -0,0 +1,3 @@ +<template> + <div id="bar">works</div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/components/Foo.vue b/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/components/Foo.vue new file mode 100644 index 000000000..3e648808c --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/components/Foo.vue @@ -0,0 +1,5 @@ +<template> + <div id="foo"> + <Bar /> + </div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/main.css b/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/main.css new file mode 100644 index 000000000..5c197d2cf --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/main.css @@ -0,0 +1,3 @@ +:root { + background-color: red; +} diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/pages/index.astro b/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/pages/index.astro new file mode 100644 index 000000000..3240cbe0f --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/pages/index.astro @@ -0,0 +1,12 @@ +--- +import Foo from '../components/Foo.vue'; +--- + +<html> + <head> + <title>Vue App Entrypoint</title> + </head> + <body> + <Foo client:load /> + </body> +</html> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/pages/unrelated.astro b/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/pages/unrelated.astro new file mode 100644 index 000000000..0952e25a7 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-css/src/pages/unrelated.astro @@ -0,0 +1,8 @@ +<html> + <head> + <title>Unrelated page</title> + </head> + <body> + <h1>I shouldn't have styles</h1> + </body> +</html> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/astro.config.mjs b/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/astro.config.mjs new file mode 100644 index 000000000..e82b7310f --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/astro.config.mjs @@ -0,0 +1,14 @@ +import vue from '@astrojs/vue'; +import { defineConfig } from 'astro/config'; +import ViteSvgLoader from 'vite-svg-loader' + +export default defineConfig({ + integrations: [vue({ + appEntrypoint: '/src/pages/_app' + })], + vite: { + plugins: [ + ViteSvgLoader(), + ], + }, +}) diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/package.json b/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/package.json new file mode 100644 index 000000000..024166e30 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/package.json @@ -0,0 +1,14 @@ +{ + "name": "@test/vue-app-entrypoint-no-export-default", + "version": "0.0.0", + "private": true, + "scripts": { + "astro": "astro" + }, + "dependencies": { + "@astrojs/vue": "workspace:*", + "astro": "workspace:*", + "vite-svg-loader": "5.1.0", + "vue": "^3.5.16" + } +} diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/src/components/Bar.vue b/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/src/components/Bar.vue new file mode 100644 index 000000000..9e690ea06 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/src/components/Bar.vue @@ -0,0 +1,3 @@ +<template> + <div id="bar">works</div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/src/components/Circle.svg b/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/src/components/Circle.svg new file mode 100644 index 000000000..cf2bd92fc --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/src/components/Circle.svg @@ -0,0 +1 @@ +<svg fill="none" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" fill="#ff0" r="40" stroke="#008000" stroke-width="4"/></svg>
\ No newline at end of file diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/src/components/Foo.vue b/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/src/components/Foo.vue new file mode 100644 index 000000000..7f6808477 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/src/components/Foo.vue @@ -0,0 +1,11 @@ +<script setup> +import Bar from './Bar.vue' +import Circle from './Circle.svg?component' +</script> + +<template> + <div id="foo"> + <Bar /> + <Circle/> + </div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/src/pages/_app.ts b/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/src/pages/_app.ts new file mode 100644 index 000000000..2fc8bde52 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/src/pages/_app.ts @@ -0,0 +1,3 @@ +export const setup = () => {} + +// no default export diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/src/pages/index.astro b/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/src/pages/index.astro new file mode 100644 index 000000000..3240cbe0f --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-no-export-default/src/pages/index.astro @@ -0,0 +1,12 @@ +--- +import Foo from '../components/Foo.vue'; +--- + +<html> + <head> + <title>Vue App Entrypoint</title> + </head> + <body> + <Foo client:load /> + </body> +</html> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-relative/astro.config.mjs b/packages/integrations/vue/test/fixtures/app-entrypoint-relative/astro.config.mjs new file mode 100644 index 000000000..05bd1b6b0 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-relative/astro.config.mjs @@ -0,0 +1,8 @@ +import vue from '@astrojs/vue'; +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + integrations: [vue({ + appEntrypoint: './src/vue.ts' + })] +}) diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-relative/package.json b/packages/integrations/vue/test/fixtures/app-entrypoint-relative/package.json new file mode 100644 index 000000000..80483c7c6 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-relative/package.json @@ -0,0 +1,12 @@ +{ + "name": "@test/vue-app-entrypoint-relative", + "version": "0.0.0", + "private": true, + "scripts": { + "astro": "astro" + }, + "dependencies": { + "@astrojs/vue": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-relative/src/components/Bar.vue b/packages/integrations/vue/test/fixtures/app-entrypoint-relative/src/components/Bar.vue new file mode 100644 index 000000000..9e690ea06 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-relative/src/components/Bar.vue @@ -0,0 +1,3 @@ +<template> + <div id="bar">works</div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-relative/src/components/Circle.svg b/packages/integrations/vue/test/fixtures/app-entrypoint-relative/src/components/Circle.svg new file mode 100644 index 000000000..cf2bd92fc --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-relative/src/components/Circle.svg @@ -0,0 +1 @@ +<svg fill="none" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" fill="#ff0" r="40" stroke="#008000" stroke-width="4"/></svg>
\ No newline at end of file diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-relative/src/components/Foo.vue b/packages/integrations/vue/test/fixtures/app-entrypoint-relative/src/components/Foo.vue new file mode 100644 index 000000000..7f6808477 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-relative/src/components/Foo.vue @@ -0,0 +1,11 @@ +<script setup> +import Bar from './Bar.vue' +import Circle from './Circle.svg?component' +</script> + +<template> + <div id="foo"> + <Bar /> + <Circle/> + </div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-relative/src/pages/index.astro b/packages/integrations/vue/test/fixtures/app-entrypoint-relative/src/pages/index.astro new file mode 100644 index 000000000..3240cbe0f --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-relative/src/pages/index.astro @@ -0,0 +1,12 @@ +--- +import Foo from '../components/Foo.vue'; +--- + +<html> + <head> + <title>Vue App Entrypoint</title> + </head> + <body> + <Foo client:load /> + </body> +</html> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-relative/src/vue.ts b/packages/integrations/vue/test/fixtures/app-entrypoint-relative/src/vue.ts new file mode 100644 index 000000000..ead516c97 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-relative/src/vue.ts @@ -0,0 +1 @@ +export default () => {} diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/astro.config.mjs b/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/astro.config.mjs new file mode 100644 index 000000000..64bb97494 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/astro.config.mjs @@ -0,0 +1,8 @@ +import vue from '@astrojs/vue'; +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + integrations: [vue({ + appEntrypoint: '/src/vue.ts' + })] +}) diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/package.json b/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/package.json new file mode 100644 index 000000000..244f9120c --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/package.json @@ -0,0 +1,12 @@ +{ + "name": "@test/vue-app-entrypoint-src-absolute", + "version": "0.0.0", + "private": true, + "scripts": { + "astro": "astro" + }, + "dependencies": { + "@astrojs/vue": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/src/components/Bar.vue b/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/src/components/Bar.vue new file mode 100644 index 000000000..9e690ea06 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/src/components/Bar.vue @@ -0,0 +1,3 @@ +<template> + <div id="bar">works</div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/src/components/Circle.svg b/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/src/components/Circle.svg new file mode 100644 index 000000000..cf2bd92fc --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/src/components/Circle.svg @@ -0,0 +1 @@ +<svg fill="none" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" fill="#ff0" r="40" stroke="#008000" stroke-width="4"/></svg>
\ No newline at end of file diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/src/components/Foo.vue b/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/src/components/Foo.vue new file mode 100644 index 000000000..7f6808477 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/src/components/Foo.vue @@ -0,0 +1,11 @@ +<script setup> +import Bar from './Bar.vue' +import Circle from './Circle.svg?component' +</script> + +<template> + <div id="foo"> + <Bar /> + <Circle/> + </div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/src/pages/index.astro b/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/src/pages/index.astro new file mode 100644 index 000000000..3240cbe0f --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/src/pages/index.astro @@ -0,0 +1,12 @@ +--- +import Foo from '../components/Foo.vue'; +--- + +<html> + <head> + <title>Vue App Entrypoint</title> + </head> + <body> + <Foo client:load /> + </body> +</html> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/src/vue.ts b/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/src/vue.ts new file mode 100644 index 000000000..ead516c97 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint-src-absolute/src/vue.ts @@ -0,0 +1 @@ +export default () => {} diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint/astro.config.mjs b/packages/integrations/vue/test/fixtures/app-entrypoint/astro.config.mjs new file mode 100644 index 000000000..e82b7310f --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint/astro.config.mjs @@ -0,0 +1,14 @@ +import vue from '@astrojs/vue'; +import { defineConfig } from 'astro/config'; +import ViteSvgLoader from 'vite-svg-loader' + +export default defineConfig({ + integrations: [vue({ + appEntrypoint: '/src/pages/_app' + })], + vite: { + plugins: [ + ViteSvgLoader(), + ], + }, +}) diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint/package.json b/packages/integrations/vue/test/fixtures/app-entrypoint/package.json new file mode 100644 index 000000000..f35415f36 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint/package.json @@ -0,0 +1,11 @@ +{ + "name": "@test/vue-app-entrypoint", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/vue": "workspace:*", + "astro": "workspace:*", + "vite-svg-loader": "5.1.0", + "vue": "^3.5.16" + } +}
\ No newline at end of file diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Bar.vue b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Bar.vue new file mode 100644 index 000000000..9e690ea06 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Bar.vue @@ -0,0 +1,3 @@ +<template> + <div id="bar">works</div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Circle.svg b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Circle.svg new file mode 100644 index 000000000..cf2bd92fc --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Circle.svg @@ -0,0 +1 @@ +<svg fill="none" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" fill="#ff0" r="40" stroke="#008000" stroke-width="4"/></svg>
\ No newline at end of file diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Foo.vue b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Foo.vue new file mode 100644 index 000000000..e07193d36 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Foo.vue @@ -0,0 +1,10 @@ +<script setup> +import Circle from './Circle.svg?component' +</script> + +<template> + <div id="foo"> + <Bar /> + <Circle/> + </div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Generics.vue b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Generics.vue new file mode 100644 index 000000000..00ceea09e --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Generics.vue @@ -0,0 +1,13 @@ +<script lang="ts" setup generic="T extends 'generic' | 'not-generic'"> +interface GenericComponentProps { + value: T +} + +defineProps<GenericComponentProps>() +</script> + +<template> + <div id="generics"> + {{ value }} + </div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/GenericsAndBlocks.vue b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/GenericsAndBlocks.vue new file mode 100644 index 000000000..7ecfdc7a0 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/GenericsAndBlocks.vue @@ -0,0 +1,18 @@ +<script lang="ts"> +export const customFormatter = (num: number) => `${num * 3}!!!` + +export type FormatNumber<T> = (num: T) => string; +</script> + +<script lang="ts" setup generic="T extends number, Formatter extends FormatNumber<T>"> +const props = defineProps<{ + value: T, + formatter: Formatter +}>() +</script> + +<template> + <div id="generics-and-blocks"> + {{ value }} {{ props.formatter(props.value) }} + </div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/MultipleScriptBlocks.vue b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/MultipleScriptBlocks.vue new file mode 100644 index 000000000..ac2ec0a3c --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/MultipleScriptBlocks.vue @@ -0,0 +1,18 @@ +<script lang="ts"> +export const doubleNumber = (num: number) => num * 2 +</script> + +<script lang="ts" setup> +defineProps({ + value: { + type: Number, + required: true + } +}) +</script> + +<template> + <div id="multiple-script-blocks"> + {{ doubleNumber(value) }} <slot /> + </div> +</template> diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint/src/pages/_app.ts b/packages/integrations/vue/test/fixtures/app-entrypoint/src/pages/_app.ts new file mode 100644 index 000000000..bbda85382 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint/src/pages/_app.ts @@ -0,0 +1,6 @@ +import type { App } from 'vue' +import Bar from '../components/Bar.vue' + +export default function setup(app: App) { + app.component('Bar', Bar); +} diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint/src/pages/index.astro b/packages/integrations/vue/test/fixtures/app-entrypoint/src/pages/index.astro new file mode 100644 index 000000000..511b626ba --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint/src/pages/index.astro @@ -0,0 +1,23 @@ +--- +import Foo from '../components/Foo.vue'; +import GenericComponent from '../components/Generics.vue'; +import GenericsAndBlocks, { customFormatter } from '../components/GenericsAndBlocks.vue'; +import MultipleScriptBlocks, { doubleNumber } from '../components/MultipleScriptBlocks.vue'; +--- + +<html> + <head> + <title>Vue App Entrypoint</title> + </head> + <body> + <Foo client:load /> + + <MultipleScriptBlocks value={1}> + {doubleNumber(2)} + </MultipleScriptBlocks> + + <GenericComponent value={'generic'} /> + + <GenericsAndBlocks value={1} formatter={customFormatter} /> + </body> +</html> diff --git a/packages/integrations/vue/test/fixtures/basics/astro.config.mjs b/packages/integrations/vue/test/fixtures/basics/astro.config.mjs new file mode 100644 index 000000000..4cc1189af --- /dev/null +++ b/packages/integrations/vue/test/fixtures/basics/astro.config.mjs @@ -0,0 +1,6 @@ +import vue from '@astrojs/vue'; +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + integrations: [vue()], +}) diff --git a/packages/integrations/vue/test/fixtures/basics/package.json b/packages/integrations/vue/test/fixtures/basics/package.json new file mode 100644 index 000000000..9cae3999c --- /dev/null +++ b/packages/integrations/vue/test/fixtures/basics/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/vue-basics", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*", + "@astrojs/vue": "workspace:*" + } +} diff --git a/packages/integrations/vue/test/fixtures/basics/public/light_walrus.avif b/packages/integrations/vue/test/fixtures/basics/public/light_walrus.avif Binary files differnew file mode 100644 index 000000000..89e1c3a14 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/basics/public/light_walrus.avif diff --git a/packages/integrations/vue/test/fixtures/basics/src/components/Foo.vue b/packages/integrations/vue/test/fixtures/basics/src/components/Foo.vue new file mode 100644 index 000000000..29db411cd --- /dev/null +++ b/packages/integrations/vue/test/fixtures/basics/src/components/Foo.vue @@ -0,0 +1,4 @@ + +<template> + <div id="foo">bar</div> +</template> diff --git a/packages/integrations/vue/test/fixtures/basics/src/components/Image.vue b/packages/integrations/vue/test/fixtures/basics/src/components/Image.vue new file mode 100644 index 000000000..5618c579b --- /dev/null +++ b/packages/integrations/vue/test/fixtures/basics/src/components/Image.vue @@ -0,0 +1,3 @@ +<template> + <img src="/light_walrus.avif" /> +</template> diff --git a/packages/integrations/vue/test/fixtures/basics/src/components/Parent.astro b/packages/integrations/vue/test/fixtures/basics/src/components/Parent.astro new file mode 100644 index 000000000..25c574998 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/basics/src/components/Parent.astro @@ -0,0 +1,4 @@ +<section> + <header></header> + <footer><slot name="footer"></slot></footer> +</section> diff --git a/packages/integrations/vue/test/fixtures/basics/src/components/WithId.vue b/packages/integrations/vue/test/fixtures/basics/src/components/WithId.vue new file mode 100644 index 000000000..2c8667696 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/basics/src/components/WithId.vue @@ -0,0 +1,9 @@ +<script setup> +import { useId } from "vue" + +const id = useId() +</script> + +<template> + <p class="vue-use-id" :id="id">{{ id }}</p> +</template>
\ No newline at end of file diff --git a/packages/integrations/vue/test/fixtures/basics/src/pages/index.astro b/packages/integrations/vue/test/fixtures/basics/src/pages/index.astro new file mode 100644 index 000000000..162b326c8 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/basics/src/pages/index.astro @@ -0,0 +1,17 @@ +--- +import Bar from '../components/Foo.vue'; +import Parent from '../components/Parent.astro'; +import WithId from '../components/WithId.vue'; +--- +<html> + <head> + <title>Testing</title> + </head> + <body> + <Parent> + <Bar slot="footer" /> + </Parent> + <WithId client:idle /> + <WithId client:idle /> + </body> +</html> diff --git a/packages/integrations/vue/test/fixtures/basics/src/pages/public.astro b/packages/integrations/vue/test/fixtures/basics/src/pages/public.astro new file mode 100644 index 000000000..011df270e --- /dev/null +++ b/packages/integrations/vue/test/fixtures/basics/src/pages/public.astro @@ -0,0 +1,5 @@ +--- +import Image from "../components/Image.vue"; +--- + +<Image /> diff --git a/packages/integrations/vue/test/test-utils.js b/packages/integrations/vue/test/test-utils.js new file mode 100644 index 000000000..512fe28dc --- /dev/null +++ b/packages/integrations/vue/test/test-utils.js @@ -0,0 +1,16 @@ +import { loadFixture as baseLoadFixture } from '../../../astro/test/test-utils.js'; + +/** + * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture + */ + +export function loadFixture(inlineConfig) { + if (!inlineConfig?.root) throw new Error("Must provide { root: './fixtures/...' }"); + + // resolve the relative root (i.e. "./fixtures/tailwindcss") to a full filepath + // without this, the main `loadFixture` helper will resolve relative to `packages/astro/test` + return baseLoadFixture({ + ...inlineConfig, + root: new URL(inlineConfig.root, import.meta.url).toString(), + }); +} diff --git a/packages/integrations/vue/test/toTsx.test.js b/packages/integrations/vue/test/toTsx.test.js new file mode 100644 index 000000000..b91b5cad1 --- /dev/null +++ b/packages/integrations/vue/test/toTsx.test.js @@ -0,0 +1,51 @@ +import assert from 'node:assert/strict'; +import { describe, it } from 'node:test'; +import { toTSX } from '../dist/editor.cjs'; + +describe('toTSX function', () => { + it('should correctly transform Vue code to TSX with comments', () => { + const vueCode = ` + <template> + <div>{{ msg }}</div> + </template> + + <script setup> + // This is a comment in script setup + // defineProps(['msg']); + // console.log('foo) + </script> + `; + + const className = 'MyComponent'; + const result = toTSX(vueCode, className); + + // Replace the expectations below with the expected result based on your logic + assert.strictEqual( + result, + `export default function ${className}__AstroComponent_(_props: Record<string, any>): any {}`, + ); + }); + it('should correctly transform Vue code to TSX', () => { + const vueCode = ` + <template> + <div @click="handleClick">{{ msg }}</div> + </template> + + <script setup> + const props defineProps({ + msg: String + }); + const handleClick = () => { + console.log('foo'); + } + </script> + `; + + const className = 'MyComponent'; + const result = toTSX(vueCode, className); + assert.strictEqual( + result.replace(/\s/g, ''), + `import{defineProps}from'vue';constProps=defineProps({msg:String})exportdefaultfunction${className}__AstroComponent_(_props:typeofProps):any{<div></div>}`, + ); + }); +}); |