Repository: vercel/next.js
File: test/development/typescript-native-preview/index.test.ts (TypeScript)

Code before:
          export default function Page() {
            return <p>hello world</p>
          }
        `,
        'tsconfig.json': JSON.stringify({
          compilerOptions: {
            target: 'ES2017',
            lib: ['dom', 'dom.iterable', 'esnext'],
            allowJs: true,
            skipLibCheck: true,
            strict: true,
            noEmit: true,
            esModuleInterop: true,
            module: 'esnext',
            moduleResolution: 'bundler',
            resolveJsonModule: true,
            isolatedModules: true,
            jsx: 'preserve',
            incremental: true,
            plugins: [{ name: 'next' }],
          },
          include: ['next-env.d.ts', '**/*.ts', '**/*.tsx'],
          exclude: ['node_modules'],
        }),
      },
      skipStart: true,
      dependencies: {
        // Install @typescript/native-preview instead of typescript
        '@typescript/native-preview': 'latest',
        '@types/react': 'latest',
        '@types/node': 'latest',
        // Explicitly exclude typescript - we want to test that Next.js
        // detects @typescript/native-preview and doesn't auto-install typescript
        typescript: undefined as any,
      },
      // Unset CI env vars since auto-install is skipped in CI
      env: {
        CI: '',
        CIRCLECI: '',
        GITHUB_ACTIONS: '',
        CONTINUOUS_INTEGRATION: '',
        RUN_ID: '',
        BUILD_NUMBER: '',
      },
    })
  })
  afterAll(() => next.destroy())

  it('should detect @typescript/native-preview and not auto-install typescript', async () => {
    await next.start()


Review comment (suggestion):
You shouldn't need the `skipStart` flag here anymore since you're in `test/development` :+1:

Code after:
      'tsconfig.json': JSON.stringify({
        compilerOptions: {
          target: 'ES2017',
          lib: ['dom', 'dom.iterable', 'esnext'],
          allowJs: true,
          skipLibCheck: true,
          strict: true,
          noEmit: true,
          esModuleInterop: true,
          module: 'esnext',
          moduleResolution: 'bundler',
          resolveJsonModule: true,
          isolatedModules: true,
          jsx: 'preserve',
          incremental: true,
          plugins: [{ name: 'next' }],
        },
        include: ['next-env.d.ts', '**/*.ts', '**/*.tsx'],
        exclude: ['node_modules'],
      }),
    },
    dependencies: {
      // Explicitly exclude typescript from default dependencies
      // so that we can test the native-preview detection
      typescript: undefined,
      // Install @typescript/native-preview instead of typescript
      '@typescript/native-preview': 'latest',
      '@types/react': 'latest',
      '@types/node': 'latest',
    },
  })

  it('should detect @typescript/native-preview and not auto-install typescript', async () => {
    // The app should still work since SWC/Turbopack handles TS compilation
    const $ = await next.render$('/')
    expect($('p').text()).toBe('hello world')

    // Wait for the info message about native-preview to be logged
    // The TypeScript verification happens asynchronously after page render
    await retry(() => {
      expect(next.cliOutput).toMatch(
        /Detected.*@typescript\/native-preview|@typescript\/native-preview.*detected/i
      )
    })

    // Should NOT show that typescript is being installed as a dependency
    // (it should recognize that native-preview is a valid alternative)
    expect(next.cliOutput).not.toMatch(/Installing.*typescript[^/]/i)
  })
})