Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions .github/workflows/framework-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ jobs:
retention-days: 1

test:
name: Framework Tests (${{ matrix.integration }})
name: Framework Tests (${{ matrix.integration.name }})
needs: [detect-integrations, build]
if: needs.detect-integrations.outputs.any-changed == 'true'
runs-on: ubuntu-latest
Expand Down Expand Up @@ -113,6 +113,15 @@ jobs:
with:
version: 10

- name: Cache pnpm store
uses: actions/cache@v5
with:
path: ~/.local/share/pnpm/store/v3
key: pnpm-${{ runner.os }}-${{ matrix.integration.name }}-${{ hashFiles('framework-tests/**/package.json') }}
restore-keys: |
pnpm-${{ runner.os }}-${{ matrix.integration.name }}-
pnpm-${{ runner.os }}-

- name: Install dependencies
run: bun install

Expand All @@ -122,8 +131,9 @@ jobs:
name: built-repo
path: packages/

- name: Run ${{ matrix.integration }} framework tests
run: cd framework-tests && bun install && bun run test -- --reporter=verbose frameworks/${{ matrix.integration }}/
- name: Run ${{ matrix.integration.name }} framework tests
run: cd framework-tests && bun install && bun run test -- --reporter=verbose frameworks/${{ matrix.integration.testPath }}
timeout-minutes: 15
# env:
# FRAMEWORK_TEST_VERBOSE: '1'
env:
NEXTJS_TURBO_ONLY: ${{ contains(matrix.integration.name, '(quick)') && '1' || '' }}
NEXT_TELEMETRY_DISABLED: '1'
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const nextConfig = {
// OUTPUT-MODE
productionBrowserSourceMaps: true,
eslint: { ignoreDuringBuilds: true },
typescript: { ignoreBuildErrors: true },
};

export default varlockNextConfigPlugin()(nextConfig);
7 changes: 6 additions & 1 deletion framework-tests/frameworks/nextjs/nextjs-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ import {
} from 'vitest';
import { FrameworkTestEnv } from '../../harness/index';

const BUNDLERS = [
const ALL_BUNDLERS = [
'webpack',
'turbopack',
];

// When running quick mode (just v16), skip webpack to cut build time in half
const BUNDLERS = process.env.NEXTJS_TURBO_ONLY
? ALL_BUNDLERS.filter((b) => b === 'turbopack')
: ALL_BUNDLERS;

const EXPORT_CONFIG = {
path: '_base/next.config.mjs' as const,
replacements: { '// OUTPUT-MODE': "output: 'export'," },
Expand Down
14 changes: 12 additions & 2 deletions framework-tests/harness/test-fixture.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
cpSync, writeFileSync, readFileSync,
cpSync, writeFileSync, readFileSync, readdirSync,
rmSync, existsSync, mkdirSync,
} from 'node:fs';
import {
Expand Down Expand Up @@ -389,7 +389,17 @@ export class FrameworkTestEnv {
* Clean build artifacts between scenarios.
*/
cleanBuildArtifacts(): void {
const artifactDirs = ['.next', 'out', 'dist', '.turbo', '.wrangler'];
// Clean .next but preserve the cache directory so turbopack/webpack
// compilation cache speeds up subsequent builds within the same fixture
const nextDir = join(this.dir, '.next');
if (existsSync(nextDir)) {
for (const entry of readdirSync(nextDir)) {
if (entry === 'cache') continue;
rmSync(join(nextDir, entry), { recursive: true, force: true });
}
}

const artifactDirs = ['out', 'dist', '.turbo', '.wrangler'];
for (const dir of artifactDirs) {
const fullPath = join(this.dir, dir);
if (existsSync(fullPath)) {
Expand Down
62 changes: 41 additions & 21 deletions scripts/detect-changed-integrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ const INTEGRATION_PACKAGES: Record<string, Array<string>> = {
astro: ['@varlock/astro-integration', '@varlock/vite-integration'],
};

// Quick test paths for integrations where full suite is expensive.
// When only core varlock or harness changes trigger the integration, run the quick
// path. When the integration's own package or test files change, run full suite.
const QUICK_TEST_PATHS: Record<string, string> = {
nextjs: 'nextjs/nextjs-v16.test.ts',
};

type IntegrationEntry = { name: string; testPath: string };

const ALL_INTEGRATIONS = Object.keys(INTEGRATION_PACKAGES);
const forceAll = process.argv.includes('--all');
const isReleasePR = process.argv.includes('--release-pr');
Expand All @@ -44,20 +53,27 @@ function writeGithubOutputs(outputs: Record<string, string>) {

const REPO_ROOT = join(import.meta.dirname, '..');

function writeResults(integrations: Array<string>) {
const anyChanged = integrations.length > 0;
function toEntry(name: string, mode: 'full' | 'quick' = 'full'): IntegrationEntry {
if (mode === 'quick' && QUICK_TEST_PATHS[name]) {
return { name: `${name} (quick)`, testPath: QUICK_TEST_PATHS[name] };
}
return { name, testPath: `${name}/` };
}

function writeResults(entries: Array<IntegrationEntry>) {
const anyChanged = entries.length > 0;
writeGithubOutputs({
'any-changed': String(anyChanged),
integrations: JSON.stringify(integrations),
integrations: JSON.stringify(entries),
});
if (!process.env.GITHUB_OUTPUT) {
console.log('Integrations to test:', integrations.length > 0 ? integrations : '(none)');
console.log('Integrations to test:', entries.length > 0 ? entries.map((e) => e.name) : '(none)');
}
}

// --all flag: test everything
// --all flag: test everything (full suite)
if (forceAll) {
writeResults(ALL_INTEGRATIONS);
writeResults(ALL_INTEGRATIONS.map((name) => toEntry(name, 'full')));
process.exit(0);
}

Expand All @@ -78,7 +94,7 @@ if (isReleasePR) {
});
} catch (e) {
console.error('Failed to diff against origin/main:', e);
writeResults(ALL_INTEGRATIONS);
writeResults(ALL_INTEGRATIONS.map((name) => toEntry(name, 'full')));
process.exit(0);
}

Expand Down Expand Up @@ -113,7 +129,7 @@ if (isReleasePR) {
} catch (e) {
console.error('Failed to diff against origin/main:', e);
// If we can't diff, fall back to running all tests
writeResults(ALL_INTEGRATIONS);
writeResults(ALL_INTEGRATIONS.map((name) => toEntry(name, 'full')));
process.exit(0);
}

Expand Down Expand Up @@ -153,7 +169,7 @@ if (isReleasePR) {
if (changedPackages.has('varlock')) {
if (isReleasePR) {
console.log('Core varlock package changed on release PR — running all integration tests');
writeResults(ALL_INTEGRATIONS);
writeResults(ALL_INTEGRATIONS.map((name) => toEntry(name, 'full')));
process.exit(0);
} else {
console.log('Core varlock package changed — triggering core-only test suites');
Expand All @@ -176,7 +192,7 @@ try {
} else if (filePath.startsWith('framework-tests/harness/') || filePath === 'framework-tests/vitest.config.ts') {
// Shared test infrastructure changed — trigger all
console.log(`Shared framework test file changed (${filePath}) — running all integration tests`);
writeResults(ALL_INTEGRATIONS);
writeResults(ALL_INTEGRATIONS.map((name) => toEntry(name, 'quick')));
process.exit(0);
}
}
Expand All @@ -188,14 +204,18 @@ try {
}

// Match changed packages to integration test suites
const integrationsList = Object.entries(INTEGRATION_PACKAGES)
.filter(([name, packages]) => {
// triggered if the test files themselves changed
if (changedTestIntegrations.has(name)) return true;
// suites with no integration packages are triggered by core varlock changes
if (packages.length === 0) return changedPackages.has('varlock');
return packages.some((pkg) => changedPackages.has(pkg));
})
.map(([name]) => name);

writeResults(integrationsList);
const entries: Array<IntegrationEntry> = [];
for (const [name, packages] of Object.entries(INTEGRATION_PACKAGES)) {
// Test files changed or integration package changed → full suite
if (changedTestIntegrations.has(name) || packages.some((pkg) => changedPackages.has(pkg))) {
entries.push(toEntry(name, 'full'));
continue;
}
// Suites with no integration packages are triggered by core varlock changes (quick)
if (packages.length === 0 && changedPackages.has('varlock')) {
entries.push(toEntry(name, 'quick'));
continue;
}
}

writeResults(entries);
Loading