import { mkdir, mkdtemp, readFile, rm, symlink, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' import { expect, it } from 'vitest' import type { TsdownBundle } from 'tsdown' import { discoverPluginDirs, watchClientPlugins } from './dev-web.ts' it('discovers dsh.client packages with sibling roles', async () => { const root = await mkdtemp(join(tmpdir(), 'dsh-dev-web-discovery-')) try { const current = join(root, 'packages', 'client', 'current') await mkdir(current, { recursive: true }) await writeFile(join(current, 'package.json'), JSON.stringify({ dsh: { bundle: { patch: './cordis.patch.yml' }, client: { platform: 'web' }, profile: { bundles: [] }, }, })) expect(discoverPluginDirs(root)).toEqual(['packages/client/current']) } finally { await rm(root, { recursive: true, force: true }) } }) it('rebuilds a client-plugin bundle after its source changes', async () => { const root = await mkdtemp(join(tmpdir(), 'dsh-dev-web-watch-')) let bundles: TsdownBundle[] = [] try { await symlink(join(import.meta.dirname, '..', 'node_modules'), join(root, 'node_modules'), 'dir') await writeFile(join(root, 'package.json'), JSON.stringify({ name: '@dsh-test/dev-web-watch', private: true, type: 'module' })) await writeFile(join(root, 'tsdown.config.ts'), ` import { defineConfig } from 'tsdown' export default defineConfig({ entry: { client: 'src.ts' }, outDir: 'lib', format: 'cjs', platform: 'browser', dts: false, clean: false, outputOptions: { entryFileNames: 'client.js' }, }) `) const sourcePath = join(root, 'src.ts') const bundlePath = join(root, 'lib/client.js') await writeFile(sourcePath, 'export const version = "watch-v1"\n') bundles = await watchClientPlugins(root, ['.'], 50) expect(await readFile(bundlePath, 'utf8')).toContain('watch-v1') await new Promise(resolve => setTimeout(resolve, 1_000)) await writeFile(sourcePath, `export const version = "watch-v2-${'x'.repeat(100)}"\n`) await expect.poll(async () => (await readFile(bundlePath, 'utf8')).includes('watch-v2-'), { timeout: 10_000, }).toBe(true) } finally { for (const bundle of bundles) await bundle[Symbol.asyncDispose]() await rm(root, { recursive: true, force: true }) } }, 20_000)