Compare commits

...

4 Commits

Author SHA1 Message Date
jackwener ca68016f8b fix(test): bootstrap self package exports in clean checkouts 2026-04-11 00:19:10 +08:00
jackwener 1298dbcc52 fix(ci): align adapter test discovery 2026-04-10 20:48:05 +08:00
jackwener 41fba155b5 test(ci): drop nested vitest regression check 2026-04-10 20:27:51 +08:00
Yuhan Lei 8cf2304c99 fix(ci): repair adapter-test and doc coverage 2026-04-10 17:05:59 +08:00
7 changed files with 101 additions and 16 deletions
+4 -4
View File
@@ -51,9 +51,9 @@ describe('linux-do topic-content', () => {
expect(command?.columns).toEqual(['content']);
});
it('keeps topic adapter as a summarized first-page reader after the split', () => {
const topicTs = fs.readFileSync(new URL('./topic.ts', import.meta.url), 'utf8');
expect(topicTs).not.toContain('main_only');
expect(topicTs).toContain('slice(0, 200)');
expect(topicTs).toContain('帖子首页摘要和回复');
const topicSource = fs.readFileSync(new URL('./topic.js', import.meta.url), 'utf8');
expect(topicSource).not.toContain('main_only');
expect(topicSource).toContain('slice(0, 200)');
expect(topicSource).toContain('帖子首页摘要和回复');
});
});
+6 -5
View File
@@ -45,6 +45,7 @@
"build-manifest": "node dist/src/build-manifest.js",
"clean-dist": "node scripts/clean-dist.cjs",
"clean-yaml": "node scripts/clean-yaml.cjs",
"prepare-test-self-exports": "node scripts/prepare-test-self-exports.mjs",
"copy-yaml": "node scripts/copy-yaml.cjs",
"start": "node dist/src/main.js",
"start:bun": "bun dist/src/main.js",
@@ -54,11 +55,11 @@
"lint": "tsc --noEmit",
"prepare": "[ -d src ] && npm run build || true",
"prepublishOnly": "npm run build",
"test": "vitest run --project unit --project extension",
"test:bun": "bun vitest run --project unit --project extension",
"test:adapter": "vitest run --project adapter",
"test:all": "vitest run",
"test:e2e": "vitest run --project e2e",
"test": "npm run prepare-test-self-exports && vitest run --project unit --project extension",
"test:bun": "node scripts/prepare-test-self-exports.mjs && bun vitest run --project unit --project extension",
"test:adapter": "npm run prepare-test-self-exports && vitest run --project adapter",
"test:all": "npm run prepare-test-self-exports && vitest run",
"test:e2e": "npm run prepare-test-self-exports && vitest run --project e2e",
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
+5
View File
@@ -30,6 +30,11 @@ for adapter_dir in "$SRC_DIR"/*/; do
adapter_name="$(basename "$adapter_dir")"
# Skip internal directories (e.g., _shared)
[[ "$adapter_name" == _* ]] && continue
# Skip helper-only directories that do not expose any top-level adapter commands.
top_level_files="$(find "$adapter_dir" -maxdepth 1 -type f | awk -F/ '{print $NF}')"
if [[ -n "$top_level_files" ]] && ! printf '%s\n' "$top_level_files" | grep -qv '^_'; then
continue
fi
total=$((total + 1))
# Check if doc exists in browser/ or desktop/ subdirectories
+26
View File
@@ -0,0 +1,26 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const pkgJson = JSON.parse(await fs.readFile(path.join(rootDir, 'package.json'), 'utf8'));
function toSourcePath(target) {
return target.replace(/^\.\/dist\//, './').replace(/\.js$/, '.ts');
}
async function writeShim(defaultTarget, sourceTarget) {
const absTarget = path.join(rootDir, defaultTarget);
const absSource = path.join(rootDir, sourceTarget);
const relSource = path.relative(path.dirname(absTarget), absSource).split(path.sep).join('/');
const sourceRef = relSource.startsWith('.') ? relSource : `./${relSource}`;
const contents = `export * from ${JSON.stringify(sourceRef)};\n`;
await fs.mkdir(path.dirname(absTarget), { recursive: true });
await fs.writeFile(absTarget, contents, 'utf8');
}
for (const target of Object.values(pkgJson.exports)) {
if (typeof target !== 'string') continue;
await writeShim(target, toSourcePath(target));
}
+51
View File
@@ -0,0 +1,51 @@
import { execFileSync } from 'node:child_process';
import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import { afterEach, describe, expect, it } from 'vitest';
const tempDirs: string[] = [];
afterEach(() => {
for (const dir of tempDirs.splice(0)) {
fs.rmSync(dir, { recursive: true, force: true });
}
});
describe('CI regression coverage', () => {
it('ignores helper-only adapter directories when checking docs coverage', () => {
const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'opencli-doc-coverage-'));
tempDirs.push(fixtureRoot);
const scriptsDir = path.join(fixtureRoot, 'scripts');
const clisDir = path.join(fixtureRoot, 'clis', 'slock');
const docsBrowserDir = path.join(fixtureRoot, 'docs', 'adapters', 'browser');
const docsDesktopDir = path.join(fixtureRoot, 'docs', 'adapters', 'desktop');
fs.mkdirSync(scriptsDir, { recursive: true });
fs.mkdirSync(clisDir, { recursive: true });
fs.mkdirSync(docsBrowserDir, { recursive: true });
fs.mkdirSync(docsDesktopDir, { recursive: true });
fs.copyFileSync(
path.join(process.cwd(), 'scripts', 'check-doc-coverage.sh'),
path.join(scriptsDir, 'check-doc-coverage.sh'),
);
fs.writeFileSync(
path.join(clisDir, '_utils.js'),
'export const helper = () => "noop";\n',
);
const output = execFileSync(
'bash',
[path.join(scriptsDir, 'check-doc-coverage.sh'), '--strict'],
{
cwd: fixtureRoot,
encoding: 'utf8',
},
);
expect(output).toContain('Doc Coverage: 0/0 adapters documented');
expect(output).toContain('All adapters have documentation');
});
});
+7 -5
View File
@@ -102,6 +102,12 @@ describe('adapter imports use package exports', () => {
});
});
function expectRealFile(target: string) {
const sourcePath = target.replace(/^\.\/dist\//, './').replace(/\.js$/, '.ts');
const fullPath = path.join(ROOT, sourcePath);
expect(fs.existsSync(fullPath), `Missing source: ${sourcePath}`).toBe(true);
}
describe('package.json exports resolve to real files', () => {
const pkgJson = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf-8'));
const exports = pkgJson.exports as Record<string, string>;
@@ -114,11 +120,7 @@ describe('package.json exports resolve to real files', () => {
it(`export "${exportPath}" → ${target} has a source file`, () => {
// Export targets point to dist/ (compiled). Verify the source .ts exists.
// dist/src/foo.js → src/foo.ts
const sourcePath = target
.replace(/^\.\/dist\//, './')
.replace(/\.js$/, '.ts');
const fullPath = path.join(ROOT, sourcePath);
expect(fs.existsSync(fullPath), `Missing source: ${sourcePath}`).toBe(true);
expectRealFile(target);
});
}
});
+2 -2
View File
@@ -9,7 +9,7 @@ export default defineConfig({
test: {
name: 'unit',
include: ['src/**/*.test.ts'],
exclude: ['clis/**/*.test.ts'],
exclude: ['src/clis/**/*.test.ts'],
sequence: { groupOrder: 0 },
},
},
@@ -23,7 +23,7 @@ export default defineConfig({
{
test: {
name: 'adapter',
include: ['clis/**/*.test.ts'],
include: ['clis/**/*.test.js', 'src/clis/**/*.test.ts'],
sequence: { groupOrder: 1 },
},
},