also looking at this
chore(deps): refresh Vue patch and verify packed SSR
#312
4 files
+75
-2
bun.lockmodified+0-0
Binary file. Nothing to show line by line.
| @@ -31,7 +31,7 @@ | ||
| 31 | 31 | "verify": "bun scripts/verify.ts", |
| 32 | 32 | "verify:packages": "bun scripts/verify-packages.ts", |
| 33 | 33 | "verify:npm": "bun scripts/npm-packages.ts", |
| 34 | "test:packages": "bun test scripts/npm-packages.test.ts scripts/mobile-package.test.ts scripts/svelte-package.test.ts scripts/scaffold-package.test.ts", | |
| 34 | "test:packages": "bun test scripts/npm-packages.test.ts scripts/mobile-package.test.ts scripts/svelte-package.test.ts scripts/vue-package.test.ts scripts/scaffold-package.test.ts", | |
| 35 | 35 | "verify:create": "bun scripts/verify-create-craft.ts", |
| 36 | 36 | "verify:cimports": "bun scripts/audit-cimports.ts", |
| 37 | 37 | "verify:docs": "bun scripts/verify-doc-links.ts", |
| @@ -0,0 +1,73 @@ | ||
| 1 | import { expect, test } from 'bun:test' | |
| 2 | import { mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from 'node:fs' | |
| 3 | import { createRequire } from 'node:module' | |
| 4 | import { tmpdir } from 'node:os' | |
| 5 | import { dirname, join, resolve } from 'node:path' | |
| 6 | ||
| 7 | test('packed Vue composables render on the server and expose usable types', () => { | |
| 8 | const root = resolve(import.meta.dir, '..') | |
| 9 | const packageDir = join(root, 'packages/vue') | |
| 10 | const temp = mkdtempSync(join(tmpdir(), 'craft-vue-package-')) | |
| 11 | const run = (args: string[], cwd = temp): void => { | |
| 12 | const result = Bun.spawnSync(args, { cwd, stdout: 'pipe', stderr: 'pipe', timeout: 30_000 }) | |
| 13 | expect(`${result.stdout}\n${result.stderr}`).not.toContain('error TS') | |
| 14 | expect(result.exitCode).toBe(0) | |
| 15 | } | |
| 16 | try { | |
| 17 | run([process.execPath, 'run', 'build'], packageDir) | |
| 18 | run([process.execPath, 'pm', 'pack', '--filename', join(temp, 'package.tgz')], packageDir) | |
| 19 | const installed = join(temp, 'node_modules/@craft-native/vue') | |
| 20 | mkdirSync(installed, { recursive: true }) | |
| 21 | run(['tar', '-xzf', join(temp, 'package.tgz'), '--strip-components=1', '-C', installed]) | |
| 22 | // Supply the actual installed peer, not a mock or a workspace Craft import. | |
| 23 | const require = createRequire(join(packageDir, 'package.json')) | |
| 24 | symlinkSync(dirname(require.resolve('vue/package.json')), join(temp, 'node_modules/vue'), 'junction') | |
| 25 | writeFileSync(join(temp, 'consumer.mjs'), ` | |
| 26 | import { strict as assert } from 'node:assert' | |
| 27 | import { createSSRApp, h } from 'vue' | |
| 28 | import { renderToString } from 'vue/server-renderer' | |
| 29 | import { useCraft, usePlatform } from '@craft-native/vue' | |
| 30 | assert.equal(typeof window, 'undefined') | |
| 31 | globalThis.setInterval = () => { throw new Error('SSR must not start bridge polling') } | |
| 32 | async function render(override) { | |
| 33 | return renderToString(createSSRApp({ | |
| 34 | setup() { | |
| 35 | const { craft, isReady } = useCraft() | |
| 36 | const { platform, loading, error } = usePlatform() | |
| 37 | assert.equal(craft.value, null) | |
| 38 | assert.equal(isReady.value, false) | |
| 39 | assert.equal(platform.value, null) | |
| 40 | assert.equal(loading.value, true) | |
| 41 | assert.equal(error.value, null) | |
| 42 | if (override) isReady.value = true | |
| 43 | return () => h('p', { 'data-ready': String(isReady.value) }, '<script>untrusted</script>') | |
| 44 | } | |
| 45 | })) | |
| 46 | } | |
| 47 | const first = await render(true) | |
| 48 | const second = await render(false) | |
| 49 | assert.ok(first.includes('data-ready="true"')) | |
| 50 | assert.ok(second.includes('data-ready="false"')) | |
| 51 | assert.ok(second.includes('<script>untrusted</script>')) | |
| 52 | assert.ok(!second.includes('<script>')) | |
| 53 | `) | |
| 54 | run([process.execPath, 'consumer.mjs']) | |
| 55 | writeFileSync(join(temp, 'consumer.mts'), ` | |
| 56 | import type { Ref } from 'vue' | |
| 57 | import { useCraft, usePlatform } from '@craft-native/vue' | |
| 58 | const ready: Ref<boolean> = useCraft().isReady | |
| 59 | const platform: Ref<{ platform: string; version: string } | null> = usePlatform().platform | |
| 60 | // @ts-expect-error readiness is boolean, not text | |
| 61 | const wrong: Ref<string> = useCraft().isReady | |
| 62 | void [ready, platform, wrong] | |
| 63 | `) | |
| 64 | run([ | |
| 65 | process.execPath, join(root, 'packages/typescript/scripts/tsc.ts'), | |
| 66 | 'consumer.mts', '--noEmit', '--strict', '--module', 'nodenext', | |
| 67 | '--moduleResolution', 'nodenext', '--target', 'esnext', '--ignoreConfig', | |
| 68 | ]) | |
| 69 | } | |
| 70 | finally { | |
| 71 | rmSync(temp, { recursive: true, force: true }) | |
| 72 | } | |
| 73 | }, 60_000) | |