mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-13 07:46:17 -08:00
refactor(tooling): [MOD-02] split library build and development into typed modules
This commit is contained in:
1 parent
28c7abb2bb
commit
401d4cdd65
36 files changed
+1644
-427
No files matched your search
@@ -1,5 +1,10 @@
|
||||
# Tests and fixture ownership
|
||||
|
||||
`yarn test:library` runs actual library builds, build-input freshness checks and the
|
||||
scaffold's generated consumers. The new build modules live in `scripts/library/`;
|
||||
`yarn typecheck:library` checks them and the retained JS/MJS entrypoints. Browser
|
||||
development/watch/error-recovery coverage is `browser/library-development.spec.js`.
|
||||
|
||||
`yarn test:scaffold` covers old plugin-generator defects, exclusive writes and
|
||||
rollback, the historical CLI path, and actual generated package builds and type
|
||||
consumers. It runs in ignored fixtures without adding a workspace or real demo;
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Browser regression entry
|
||||
|
||||
`library-development.spec.js` starts the actual typed development runner on an
|
||||
isolated fixture port. It checks generated TS/Less/SVG/inline-worker assets,
|
||||
automatic reload on edits and recovery after a compiler error in all three
|
||||
engines. It owns and stops only its child server, never the user's port 8082
|
||||
session. This is development-tool validation, not media playback acceptance.
|
||||
|
||||
`site-loading.spec.js` covers actual desktop/mobile loading, dependency order,
|
||||
failure/retry/AMD restoration, example priority, repeated Run and stale responses,
|
||||
plus Run Code and language routing. External analytics/ads are inert test routes;
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
import { spawn } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import net from 'node:net'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url'
|
||||
import { expect, test } from '@playwright/test'
|
||||
|
||||
const root = fileURLToPath(new URL('../../', import.meta.url))
|
||||
const cache = path.join(root, 'refactor/.cache')
|
||||
|
||||
function removeFixture(directory) {
|
||||
if (fs.realpathSync(directory) !== directory || path.dirname(directory) !== fs.realpathSync(cache))
|
||||
throw new Error(`Refusing redirected fixture cleanup: ${directory}`)
|
||||
fs.rmSync(directory, { recursive: true, force: true })
|
||||
}
|
||||
|
||||
async function freePort() {
|
||||
const server = net.createServer()
|
||||
await new Promise((resolve, reject) => {
|
||||
server.once('error', reject)
|
||||
server.listen(0, resolve)
|
||||
})
|
||||
const port = server.address().port
|
||||
await new Promise(resolve => server.close(resolve))
|
||||
return port
|
||||
}
|
||||
|
||||
test('typed development builds real assets and workers, watches edits and recovers from compilation errors', async ({ page }, testInfo) => {
|
||||
test.setTimeout(60000)
|
||||
const directory = fs.mkdtempSync(path.join(cache, 'library-development-'))
|
||||
const name = 'artplayer-plugin-build-probe'
|
||||
const source = path.join(directory, 'packages', name, 'src')
|
||||
fs.mkdirSync(source, { recursive: true })
|
||||
fs.cpSync(path.join(root, 'refactor/fixtures/build'), source, { recursive: true })
|
||||
fs.writeFileSync(path.join(source, '../package.json'), JSON.stringify({ name, version: '1.0.0' }))
|
||||
fs.mkdirSync(path.join(directory, 'docs'))
|
||||
fs.writeFileSync(path.join(directory, 'docs/index.html'), `<!doctype html><html><body><main></main>
|
||||
<script src="/uncompiled/${name}/index.js"></script><script>
|
||||
window.probe = artplayerPluginBuildProbe();
|
||||
document.querySelector('main').textContent = String(probe.value);
|
||||
</script></body></html>`)
|
||||
const port = await freePort()
|
||||
const url = `http://localhost:${port}`
|
||||
const module = pathToFileURL(path.join(root, 'scripts/library/development.ts')).href
|
||||
const code = `import { runDevelop } from ${JSON.stringify(module)};
|
||||
process.argv = [process.execPath, 'fixture.js', '${name}', '--no-open'];
|
||||
await runDevelop({port:${port}});`
|
||||
const launcher = path.join(directory, 'launch.mjs')
|
||||
fs.writeFileSync(launcher, code)
|
||||
const child = spawn(process.execPath, [launcher], { cwd: directory, windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] })
|
||||
let output = ''
|
||||
child.stdout.on('data', (data) => {
|
||||
output += data
|
||||
})
|
||||
child.stderr.on('data', (data) => {
|
||||
output += data
|
||||
})
|
||||
const exited = new Promise(resolve => child.once('exit', resolve))
|
||||
try {
|
||||
await expect.poll(() => output, { timeout: 20000 }).toContain('Watching')
|
||||
expect(child.exitCode).toBeNull()
|
||||
await page.goto(url)
|
||||
await expect(page.locator('main')).toHaveText('42')
|
||||
expect(await page.evaluate(() => window.probe.css)).toContain('#123abc')
|
||||
expect(await page.evaluate(() => window.probe.svg)).toContain('<svg')
|
||||
const workerResult = await page.evaluate(() => new Promise((resolve, reject) => {
|
||||
const worker = window.probe.createWorker()
|
||||
worker.onmessage = ({ data }) => {
|
||||
worker.terminate()
|
||||
resolve(data)
|
||||
}
|
||||
worker.onerror = (error) => {
|
||||
worker.terminate()
|
||||
reject(new Error(error.message))
|
||||
}
|
||||
worker.postMessage(21)
|
||||
}))
|
||||
expect(workerResult).toBe(22)
|
||||
const entry = path.join(source, 'index.ts')
|
||||
const original = fs.readFileSync(entry, 'utf8')
|
||||
const before = output.length
|
||||
fs.writeFileSync(entry, original.replace('add(20, 22)', 'add(20, 23)'))
|
||||
await expect.poll(() => output.slice(before), { timeout: 15000 }).toContain('Built in')
|
||||
await expect(page.locator('main')).toHaveText('43')
|
||||
const valid = output.length
|
||||
fs.writeFileSync(entry, 'export default function broken( {')
|
||||
await expect.poll(() => output.slice(valid), { timeout: 15000 }).toContain('Build error')
|
||||
expect(child.exitCode).toBeNull()
|
||||
const failed = output.length
|
||||
fs.writeFileSync(entry, original.replace('add(20, 22)', 'add(20, 24)'))
|
||||
await expect.poll(() => output.slice(failed), { timeout: 15000 }).toContain('Built in')
|
||||
await expect(page.locator('main')).toHaveText('44')
|
||||
}
|
||||
finally {
|
||||
await testInfo.attach('development-server.log', { body: output, contentType: 'text/plain' })
|
||||
child.kill()
|
||||
await exited
|
||||
removeFixture(directory)
|
||||
}
|
||||
})
|
||||
@@ -87,6 +87,7 @@ test('performance refuses stale sources, build tools and altered installed bundl
|
||||
'scripts/build.js': 'build fixture\n',
|
||||
'scripts/utils.js': 'utils fixture\n',
|
||||
'scripts/projects.js': 'projects fixture\n',
|
||||
'scripts/library/config.ts': 'typed build fixture\n',
|
||||
}
|
||||
for (const [file, content] of Object.entries(toolchain)) {
|
||||
write(path.join(root, file), content)
|
||||
@@ -115,6 +116,12 @@ test('performance refuses stale sources, build tools and altered installed bundl
|
||||
write(path.join(root, 'scripts/build.js'), 'changed compiler\n')
|
||||
assert.throws(() => verifyPerformanceArtifacts(root, map), /Stale build input/)
|
||||
write(path.join(root, 'scripts/build.js'), toolchain['scripts/build.js'])
|
||||
write(path.join(root, 'scripts/library/config.ts'), 'changed TS config\n')
|
||||
assert.throws(() => verifyPerformanceArtifacts(root, map), /Stale library build inputs/)
|
||||
write(path.join(root, 'scripts/library/config.ts'), toolchain['scripts/library/config.ts'])
|
||||
write(path.join(snapshot, 'scripts/library/removed.ts'), 'stale module\n')
|
||||
assert.throws(() => verifyPerformanceArtifacts(root, map), /Stale library build inputs/)
|
||||
fs.unlinkSync(path.join(snapshot, 'scripts/library/removed.ts'))
|
||||
write(path.join(output, 'artifacts/artplayer/dist/artplayer.js'), 'changed bundle\n')
|
||||
assert.throws(() => verifyPerformanceArtifacts(root, map), /Installed performance artifact changed/)
|
||||
})
|
||||
Reference in new issue
Block a user