diff --git a/.github/scripts/tsconfig.json b/.github/scripts/tsconfig.json new file mode 100644 index 000000000000..2529f53ec0ef --- /dev/null +++ b/.github/scripts/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "allowJs": true + } +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 32068609d8f0..632c12e85ba8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -141,7 +141,7 @@ jobs: run: pnpm run publint - name: Type-check test files - run: pnpm -C packages/astro run typecheck:tests + run: pnpm run typecheck:tests test: name: 'Test (${{ matrix.TEST_SUITE.name }}): ${{ matrix.os }} (node@${{ matrix.NODE_VERSION }})' diff --git a/knip.js b/knip.js index d2b146c21ad1..5e28a0378e0a 100644 --- a/knip.js +++ b/knip.js @@ -1,5 +1,5 @@ // @ts-check -const testEntry = 'test/**/*.test.js'; +const testEntry = 'test/**/*.test.{js,ts}'; /** @type {import('knip').KnipConfig} */ export default { diff --git a/package.json b/package.json index e5d8b2057448..9ac10514cd59 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "test:e2e": "cd packages/astro && pnpm playwright install firefox && pnpm run test:e2e", "test:e2e:match": "cd packages/astro && pnpm playwright install firefox && pnpm run test:e2e:match", "test:e2e:hosts": "turbo run test:hosted", + "typecheck:tests": "pnpm -r typecheck:tests", "benchmark": "astro-benchmark", "lint": "biome lint && knip && eslint . --report-unused-disable-directives-severity=warn --concurrency=auto", "lint:ci": "knip && pnpm run eslint:ci", diff --git a/packages/astro/package.json b/packages/astro/package.json index 5b72f702acc3..113092f9dea9 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -112,8 +112,8 @@ "test:e2e:match": "playwright test -g", "test:e2e:chrome": "playwright test", "test:e2e:firefox": "playwright test --config playwright.firefox.config.js", - "test:types": "tsc --project test/types/tsconfig.json", - "typecheck:tests": "tsc --project tsconfig.test.json", + "test:types": "tsc --build test/types/tsconfig.json", + "typecheck:tests": "tsc --build tsconfig.test.json", "test:unit": "astro-scripts test \"test/units/**/*.test.ts\" --strip-types --teardown ./test/units/teardown.ts", "test:integration": "pnpm run test:integration:js && pnpm run test:integration:ts", "test:integration:js": "astro-scripts test \"test/*.test.js\"", diff --git a/packages/astro/test/types/schemas.ts b/packages/astro/test/types/schemas.ts index 5059f763b167..3f84ba2a947a 100644 --- a/packages/astro/test/types/schemas.ts +++ b/packages/astro/test/types/schemas.ts @@ -1,9 +1,9 @@ import { describe, it } from 'node:test'; import { expectTypeOf } from 'expect-type'; import type * as z from 'zod/v4'; -import { type FontProviderSchema, FontFamilySchema } from '../../src/assets/fonts/config.js'; -import type { FontProvider, FontFamily } from '../../src/assets/fonts/types.js'; -import type { CacheSchema, RouteRulesSchema } from '../../src/core/cache/config.js'; +import { type FontProviderSchema, FontFamilySchema } from '../../dist/assets/fonts/config.js'; +import type { FontProvider, FontFamily } from '../../dist/assets/fonts/types.js'; +import type { CacheSchema, RouteRulesSchema } from '../../dist/core/cache/config.js'; import type { CacheProviderConfig, RouteRules } from '../../dist/core/cache/types.js'; import type { SessionDriverConfigSchema } from '../../dist/core/session/config.js'; import type { SessionDriverConfig } from '../../dist/core/session/types.js'; diff --git a/packages/astro/test/types/tsconfig.json b/packages/astro/test/types/tsconfig.json index cc320a61e407..249c1cc68986 100644 --- a/packages/astro/test/types/tsconfig.json +++ b/packages/astro/test/types/tsconfig.json @@ -1,8 +1,8 @@ { "extends": "../../../../tsconfig.base.json", "compilerOptions": { + "composite": true, "allowJs": true, - "emitDeclarationOnly": false, - "noEmit": true + "emitDeclarationOnly": false } } diff --git a/packages/astro/tsconfig.json b/packages/astro/tsconfig.json index 2eaf394f8501..473fa36b5f04 100644 --- a/packages/astro/tsconfig.json +++ b/packages/astro/tsconfig.json @@ -3,11 +3,13 @@ "include": ["src", "dev-only.d.ts"], "exclude": ["dist"], "compilerOptions": { + "composite": true, "rootDir": "./src", "allowJs": true, "declarationDir": "./dist", "outDir": "./dist", "jsx": "preserve", + "tsBuildInfoFile": "${configDir}/dist/._cache/tsconfig/tsbuildinfo.json", "erasableSyntaxOnly": true } } diff --git a/packages/astro/tsconfig.test.json b/packages/astro/tsconfig.test.json index 65a0ab0b0c44..630c07551762 100644 --- a/packages/astro/tsconfig.test.json +++ b/packages/astro/tsconfig.test.json @@ -1,12 +1,30 @@ { "extends": "../../tsconfig.base.json", - "include": ["test/units/**/*.ts"], + "include": [ + "test/units/**/*.ts", + "test/test-adapter.js", + "test/test-image-service.js", + "test/test-plugins.js", + "test/test-prerenderer.js", + "test/test-remote-image-service.js", + "test/test-utils.js", + "package.json" + ], "exclude": ["test/units/_temp-fixtures/**", "test/fixtures/**"], "compilerOptions": { - "noEmit": true, + "types": ["vite/client", "node"], + "composite": true, "allowJs": true, "noUnusedLocals": false, "noUnusedParameters": false, "rewriteRelativeImportExtensions": true - } + }, + "references": [ + { + "path": "./tsconfig.json" + }, + { + "path": "../../scripts/tsconfig.json" + } + ] } diff --git a/packages/integrations/react/package.json b/packages/integrations/react/package.json index 536fc8189f1b..bdd9f52439a0 100644 --- a/packages/integrations/react/package.json +++ b/packages/integrations/react/package.json @@ -36,7 +36,8 @@ "build": "astro-scripts build \"src/**/*.ts\" && tsc", "build:ci": "astro-scripts build \"src/**/*.ts\"", "dev": "astro-scripts dev \"src/**/*.ts\"", - "test": "astro-scripts test \"test/**/*.test.js\"" + "test": "astro-scripts test \"test/**/*.test.ts\"", + "typecheck:tests": "tsc --build tsconfig.test.json" }, "dependencies": { "@astrojs/internal-helpers": "workspace:*", diff --git a/packages/integrations/react/test/parsed-react-children.test.js b/packages/integrations/react/test/parsed-react-children.test.ts similarity index 100% rename from packages/integrations/react/test/parsed-react-children.test.js rename to packages/integrations/react/test/parsed-react-children.test.ts diff --git a/packages/integrations/react/test/react-19-preloads.test.js b/packages/integrations/react/test/react-19-preloads.test.ts similarity index 96% rename from packages/integrations/react/test/react-19-preloads.test.js rename to packages/integrations/react/test/react-19-preloads.test.ts index ccca49827066..80842384ae1f 100644 --- a/packages/integrations/react/test/react-19-preloads.test.js +++ b/packages/integrations/react/test/react-19-preloads.test.ts @@ -7,7 +7,7 @@ test.describe('React 19 SSR integration', () => { const fixture = await loadFixture({ root: new URL('./fixtures/react-19-preloads/', import.meta.url), }); - await fixture.build(); + await fixture.build({}); const html = await fixture.readFile('/index.html'); const islandPattern = /]*>([\s\S]*?)<\/astro-island>/; diff --git a/packages/integrations/react/test/react-component.test.js b/packages/integrations/react/test/react-component.test.ts similarity index 87% rename from packages/integrations/react/test/react-component.test.js rename to packages/integrations/react/test/react-component.test.ts index 67f2fbef979c..5ef2ae478d5a 100644 --- a/packages/integrations/react/test/react-component.test.js +++ b/packages/integrations/react/test/react-component.test.ts @@ -1,9 +1,14 @@ import assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; import { load as cheerioLoad } from 'cheerio'; -import { isWindows, loadFixture } from '../../../astro/test/test-utils.js'; +import { + isWindows, + loadFixture, + type Fixture, + type DevServer, +} from '../../../astro/test/test-utils.js'; -let fixture; +let fixture: Fixture; describe('React Components', () => { before(async () => { @@ -14,7 +19,7 @@ describe('React Components', () => { describe('build', () => { before(async () => { - await fixture.build(); + await fixture.build({}); }); it('Can load React', async () => { @@ -144,8 +149,7 @@ describe('React Components', () => { if (isWindows) return; describe('dev', () => { - /** @type {import('../../../astro/test/test-utils.js').Fixture} */ - let devServer; + let devServer: DevServer; before(async () => { devServer = await fixture.startDevServer(); @@ -156,7 +160,8 @@ describe('React Components', () => { }); it('scripts proxy correctly', async () => { - const html = await fixture.fetch('/').then((res) => res.text()); + const response = await fixture.fetch('/'); + const html: string = await response.text(); const $ = cheerioLoad(html); for (const script of $('script').toArray()) { @@ -168,9 +173,10 @@ describe('React Components', () => { // TODO: move this to separate dev test? it.skip('Throws helpful error message on window SSR', async () => { - const html = await fixture.fetch('/window/index.html'); + const response = await fixture.fetch('/window/index.html'); + const html: string = await response.text(); assert.ok( - (await html.text()).includes( + html.includes( `[/window] The window object is not available during server-side rendering (SSR). Try using \`import.meta.env.SSR\` to write SSR-friendly code. @@ -181,19 +187,26 @@ describe('React Components', () => { // In moving over to Vite, the jsx-runtime import is now obscured. TODO: update the method of finding this. it.skip('uses the new JSX transform', async () => { - const html = await fixture.fetch('/index.html'); + const response = await fixture.fetch('/index.html'); + const html: string = await response.text(); // Grab the imports const exp = /import\("(.+?)"\)/g; - let match, componentUrl; + let match, componentUrl: string | undefined; while ((match = exp.exec(html))) { if (match[1].includes('Research.js')) { componentUrl = match[1]; break; } } + if (!componentUrl) { + throw new Error('Could not find component URL in HTML'); + } + const component = await fixture.readFile(componentUrl); - const jsxRuntime = component.imports.filter((i) => i.specifier.includes('jsx-runtime')); + // @ts-expect-error: error TS2339: Property 'imports' does not exist on type 'string'. + const imports = component.imports; + const jsxRuntime = imports.filter((i: any) => i.specifier.includes('jsx-runtime')); // test 1: react/jsx-runtime is used for the component assert.ok(jsxRuntime); diff --git a/packages/integrations/react/tsconfig.test.json b/packages/integrations/react/tsconfig.test.json new file mode 100644 index 000000000000..27c89c5fe7a7 --- /dev/null +++ b/packages/integrations/react/tsconfig.test.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../tsconfig.base.json", + "include": ["test/**/*.ts"], + "exclude": ["test/fixtures/**"], + "compilerOptions": { + "noEmit": true, + "allowJs": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "rewriteRelativeImportExtensions": true + }, + "references": [ + { + "path": "../../astro/tsconfig.test.json" + } + ] +} diff --git a/scripts/jsconfig.json b/scripts/jsconfig.json deleted file mode 100644 index 0caa704a7a8e..000000000000 --- a/scripts/jsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "compilerOptions": { - "declaration": true, - "strict": true, - "module": "esnext", - "moduleResolution": "nodenext", - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "target": "esnext" - } -} diff --git a/scripts/testing/github-test-reporter.js b/scripts/testing/github-test-reporter.js index 38f1c813bca0..0351b6fd5d92 100644 --- a/scripts/testing/github-test-reporter.js +++ b/scripts/testing/github-test-reporter.js @@ -20,7 +20,7 @@ export default new Transform({ file: event.data.file, line: event.data.line, column: event.data.column, - isSuite: event.data.details.type !== 'test', + isSuite: event.data.details.type === 'suite', }); break; } diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json new file mode 100644 index 000000000000..00ed7dd5d654 --- /dev/null +++ b/scripts/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "allowJs": true + }, + "references": [ + { + "path": "../.github/scripts/tsconfig.json" + } + ] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index bb1f2630431b..1600925b31ce 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -14,6 +14,7 @@ "noUnusedLocals": true, "noUnusedParameters": true, "erasableSyntaxOnly": true, + "outDir": "${configDir}/node_modules/.cache/tsconfig/out", "types": ["node"] } }