Files
kjol/tools/tsgo/internal/execute/tsctests/tscwatch_test.go
2026-07-09 16:50:43 -04:00

689 lines
26 KiB
Go

package tsctests
import (
"fmt"
"strings"
"testing"
"github.com/microsoft/typescript-go/internal/vfs/vfstest"
)
func TestWatch(t *testing.T) {
t.Parallel()
bunDependencyTest := func() *tscInput {
files := FileMap{}
var index strings.Builder
var fileNames strings.Builder
fileNames.WriteString(`"index.ts"`)
for i := range 12 {
name := fmt.Sprintf("pkg%d", i)
value := fmt.Sprintf("value%d", i)
index.WriteString(fmt.Sprintf(`import { %[1]s } from "./node_modules/.bun/%[2]s/index"; %[1]s;`, value, name))
index.WriteString("\n")
files["/home/src/workspaces/project/node_modules/.bun/"+name+"/index.ts"] = fmt.Sprintf("export const %s = %d;", value, i)
fileNames.WriteString(fmt.Sprintf(`, "node_modules/.bun/%s/index.ts"`, name))
}
files["/home/src/workspaces/project/index.ts"] = index.String()
files["/home/src/workspaces/project/tsconfig.json"] = fmt.Sprintf(`{
"compilerOptions": {},
"files": [%s]
}`, fileNames.String())
return &tscInput{
subScenario: "watch handles many bun dependency files",
files: files,
commandLineArgs: []string{"--watch"},
}
}
testCases := []*tscInput{
{
subScenario: "watch with no tsconfig",
files: FileMap{
"/home/src/workspaces/project/index.ts": "",
},
commandLineArgs: []string{"index.ts", "--watch"},
},
{
subScenario: "watch with tsconfig and incremental",
files: FileMap{
"/home/src/workspaces/project/index.ts": "",
"/home/src/workspaces/project/tsconfig.json": "{}",
},
commandLineArgs: []string{"--watch", "--incremental"},
},
bunDependencyTest(),
{
subScenario: "watch skips build when no files change",
files: FileMap{
"/home/src/workspaces/project/index.ts": `const x: number = 1;`,
"/home/src/workspaces/project/tsconfig.json": "{}",
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
noChange,
},
},
{
subScenario: "watch rebuilds when file is modified",
files: FileMap{
"/home/src/workspaces/project/index.ts": `const x: number = 1;`,
"/home/src/workspaces/project/tsconfig.json": "{}",
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("modify file", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/index.ts", `const x: number = 2;`)
}),
},
},
{
subScenario: "watch rebuilds when source file is deleted",
files: FileMap{
"/home/src/workspaces/project/a.ts": `import { b } from "./b";`,
"/home/src/workspaces/project/b.ts": `export const b = 1;`,
"/home/src/workspaces/project/tsconfig.json": "{}",
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
{
caption: "delete imported file",
edit: func(sys *TestSys) {
sys.removeNoError("/home/src/workspaces/project/b.ts")
},
expectedDiff: "incremental resolves to .js output from prior build (TS7016) while clean build cannot find module at all (TS2307)",
},
},
},
{
subScenario: "watch detects new file resolving failed import",
files: FileMap{
"/home/src/workspaces/project/a.ts": `import { b } from "./b";`,
"/home/src/workspaces/project/tsconfig.json": "{}",
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("create missing file", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/b.ts", `export const b = 1;`)
}),
},
},
// Directory-level change detection via imports
{
subScenario: "watch detects imported file added in new directory",
files: FileMap{
"/home/src/workspaces/project/index.ts": `import { util } from "./lib/util";`,
"/home/src/workspaces/project/tsconfig.json": "{}",
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("create directory and imported file", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/lib/util.ts", `export const util = "hello";`)
}),
},
},
{
subScenario: "watch detects imported directory removed",
files: FileMap{
"/home/src/workspaces/project/index.ts": `import { util } from "./lib/util";`,
"/home/src/workspaces/project/lib/util.ts": `export const util = "hello";`,
"/home/src/workspaces/project/tsconfig.json": "{}",
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
{
caption: "remove directory with imported file",
edit: func(sys *TestSys) {
sys.removeNoError("/home/src/workspaces/project/lib/util.ts")
},
expectedDiff: "incremental resolves to .js output from prior build (TS7016) while clean build cannot find module at all (TS2307)",
},
},
},
{
subScenario: "watch detects import path restructured",
files: FileMap{
"/home/src/workspaces/project/index.ts": `import { util } from "./lib/util";`,
"/home/src/workspaces/project/lib/util.ts": `export const util = "v1";`,
"/home/src/workspaces/project/tsconfig.json": "{}",
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("move file to new path and update import", func(sys *TestSys) {
sys.removeNoError("/home/src/workspaces/project/lib/util.ts")
sys.writeFileNoError("/home/src/workspaces/project/src/util.ts", `export const util = "v2";`)
sys.writeFileNoError("/home/src/workspaces/project/index.ts", `import { util } from "./src/util";`)
}),
},
},
// tsconfig include/exclude change detection
{
subScenario: "watch rebuilds when tsconfig include pattern adds file",
files: FileMap{
"/home/src/workspaces/project/index.ts": `const x = 1;`,
"/home/src/workspaces/project/tsconfig.json": `{
"compilerOptions": {},
"include": ["*.ts"]
}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("widen include pattern to add src dir", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/src/extra.ts", `export const extra = 2;`)
sys.writeFileNoError("/home/src/workspaces/project/tsconfig.json", `{
"compilerOptions": {},
"include": ["*.ts", "src/**/*.ts"]
}`)
}),
},
},
{
subScenario: "watch rebuilds when tsconfig is modified to change strict",
files: FileMap{
"/home/src/workspaces/project/index.ts": `const x = null; const y: string = x;`,
"/home/src/workspaces/project/tsconfig.json": `{}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("enable strict mode", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/tsconfig.json", `{"compilerOptions": {"strict": true}}`)
}),
},
},
// Path resolution: tsconfig include pointing to non-existent directory
{
subScenario: "watch detects file added to previously non-existent include path",
files: FileMap{
"/home/src/workspaces/project/index.ts": `const x = 1;`,
"/home/src/workspaces/project/tsconfig.json": `{
"compilerOptions": {},
"include": ["index.ts", "src/**/*.ts"]
}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("create src dir with ts file matching include", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/src/helper.ts", `export const helper = "added";`)
}),
},
},
{
subScenario: "watch detects new file in existing include directory",
files: FileMap{
"/home/src/workspaces/project/src/a.ts": `export const a = 1;`,
"/home/src/workspaces/project/tsconfig.json": `{
"compilerOptions": {},
"include": ["src/**/*.ts"]
}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("add new file to existing src directory", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/src/b.ts", `export const b = 2;`)
}),
},
},
// Wildcard include: nested subdirectory detection
{
subScenario: "watch detects file added in new nested subdirectory",
files: FileMap{
"/home/src/workspaces/project/src/a.ts": `export const a = 1;`,
"/home/src/workspaces/project/tsconfig.json": `{
"compilerOptions": {},
"include": ["src/**/*.ts"]
}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("create nested dir with ts file", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/src/deep/nested/util.ts", `export const util = "nested";`)
}),
},
},
{
subScenario: "watch detects file added in multiple new subdirectories simultaneously",
files: FileMap{
"/home/src/workspaces/project/src/a.ts": `export const a = 1;`,
"/home/src/workspaces/project/tsconfig.json": `{
"compilerOptions": {},
"include": ["src/**/*.ts"]
}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("create multiple new subdirs with files", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/src/models/user.ts", `export interface User { name: string; }`)
sys.writeFileNoError("/home/src/workspaces/project/src/utils/format.ts", `export function format(s: string): string { return s.trim(); }`)
}),
},
},
{
subScenario: "watch detects nested subdirectory removed and recreated",
files: FileMap{
"/home/src/workspaces/project/src/lib/helper.ts": `export const helper = "v1";`,
"/home/src/workspaces/project/tsconfig.json": `{
"compilerOptions": {},
"include": ["src/**/*.ts"]
}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
{
caption: "remove nested dir",
expectedDiff: "incremental has prior state and does not report no-inputs error",
edit: func(sys *TestSys) {
sys.removeNoError("/home/src/workspaces/project/src/lib/helper.ts")
},
},
newTscEdit("recreate nested dir with new content", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/src/lib/helper.ts", `export const helper = "v2";`)
}),
},
},
// Path resolution: import from non-existent node_modules package
{
subScenario: "watch detects node modules package added",
files: FileMap{
"/home/src/workspaces/project/index.ts": `import { lib } from "mylib";`,
"/home/src/workspaces/project/tsconfig.json": `{}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("install package in node_modules", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/node_modules/mylib/package.json", `{"name": "mylib", "main": "index.js", "types": "index.d.ts"}`)
sys.writeFileNoError("/home/src/workspaces/project/node_modules/mylib/index.js", `exports.lib = "hello";`)
sys.writeFileNoError("/home/src/workspaces/project/node_modules/mylib/index.d.ts", `export declare const lib: string;`)
}),
},
},
// Path resolution: node_modules package removed
{
subScenario: "watch detects node modules package removed",
files: FileMap{
"/home/src/workspaces/project/index.ts": `import { lib } from "mylib";`,
"/home/src/workspaces/project/tsconfig.json": `{}`,
"/home/src/workspaces/project/node_modules/mylib/package.json": `{"name": "mylib", "main": "index.js", "types": "index.d.ts"}`,
"/home/src/workspaces/project/node_modules/mylib/index.js": `exports.lib = "hello";`,
"/home/src/workspaces/project/node_modules/mylib/index.d.ts": `export declare const lib: string;`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
{
caption: "remove node_modules package",
edit: func(sys *TestSys) {
sys.removeNoError("/home/src/workspaces/project/node_modules/mylib/index.d.ts")
sys.removeNoError("/home/src/workspaces/project/node_modules/mylib/index.js")
sys.removeNoError("/home/src/workspaces/project/node_modules/mylib/package.json")
},
},
},
},
// Path resolution: node_modules removed then reinstalled (npm ci after rm -rf)
{
subScenario: "watch detects node modules reinstalled after deletion",
files: FileMap{
"/home/src/workspaces/project/index.ts": `import { lib } from "mylib";`,
"/home/src/workspaces/project/tsconfig.json": `{}`,
"/home/src/workspaces/project/node_modules/mylib/package.json": `{"name": "mylib", "main": "index.js", "types": "index.d.ts"}`,
"/home/src/workspaces/project/node_modules/mylib/index.js": `exports.lib = "hello";`,
"/home/src/workspaces/project/node_modules/mylib/index.d.ts": `export declare const lib: string;`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
{
caption: "delete node_modules entirely",
edit: func(sys *TestSys) {
sys.removeNoError("/home/src/workspaces/project/node_modules/mylib/index.d.ts")
sys.removeNoError("/home/src/workspaces/project/node_modules/mylib/index.js")
sys.removeNoError("/home/src/workspaces/project/node_modules/mylib/package.json")
},
},
newTscEdit("reinstall node_modules", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/node_modules/mylib/package.json", `{"name": "mylib", "main": "index.js", "types": "index.d.ts"}`)
sys.writeFileNoError("/home/src/workspaces/project/node_modules/mylib/index.js", `exports.lib = "hello";`)
sys.writeFileNoError("/home/src/workspaces/project/node_modules/mylib/index.d.ts", `export declare const lib: string;`)
}),
},
},
// Config file lifecycle
{
subScenario: "watch handles tsconfig deleted",
files: FileMap{
"/home/src/workspaces/project/index.ts": `const x = 1;`,
"/home/src/workspaces/project/tsconfig.json": `{}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
{
caption: "delete tsconfig",
expectedDiff: "incremental reports config read error while clean build without tsconfig prints usage help",
edit: func(sys *TestSys) {
sys.removeNoError("/home/src/workspaces/project/tsconfig.json")
},
},
},
},
{
subScenario: "watch handles tsconfig with extends base modified",
files: FileMap{
"/home/src/workspaces/project/index.ts": `const x = null; const y: string = x;`,
"/home/src/workspaces/project/base.json": `{
"compilerOptions": { "strict": false }
}`,
"/home/src/workspaces/project/tsconfig.json": `{
"extends": "./base.json"
}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("modify base config to enable strict", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/base.json", `{
"compilerOptions": { "strict": true }
}`)
}),
},
},
{
subScenario: "watch rebuilds when tsconfig is touched but content unchanged",
files: FileMap{
"/home/src/workspaces/project/index.ts": `const x = 1;`,
"/home/src/workspaces/project/tsconfig.json": `{}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("touch tsconfig without changing content", func(sys *TestSys) {
content := sys.readFileNoError("/home/src/workspaces/project/tsconfig.json")
sys.writeFileNoError("/home/src/workspaces/project/tsconfig.json", content)
}),
},
},
{
subScenario: "watch with tsconfig files list entry deleted",
files: FileMap{
"/home/src/workspaces/project/a.ts": `export const a = 1;`,
"/home/src/workspaces/project/b.ts": `export const b = 2;`,
"/home/src/workspaces/project/tsconfig.json": `{
"compilerOptions": {},
"files": ["a.ts", "b.ts"]
}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("delete file listed in files array", func(sys *TestSys) {
sys.removeNoError("/home/src/workspaces/project/b.ts")
}),
},
},
// Module resolution & dependencies
{
subScenario: "watch detects module going missing then coming back",
files: FileMap{
"/home/src/workspaces/project/index.ts": `import { util } from "./util";`,
"/home/src/workspaces/project/util.ts": `export const util = "v1";`,
"/home/src/workspaces/project/tsconfig.json": `{}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
{
caption: "delete util module",
edit: func(sys *TestSys) {
sys.removeNoError("/home/src/workspaces/project/util.ts")
},
expectedDiff: "incremental resolves to .js output from prior build while clean build cannot find module",
},
newTscEdit("recreate util module with new content", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/util.ts", `export const util = "v2";`)
}),
},
},
{
subScenario: "watch detects scoped package installed",
files: FileMap{
"/home/src/workspaces/project/index.ts": `import { lib } from "@scope/mylib";`,
"/home/src/workspaces/project/tsconfig.json": `{}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("install scoped package", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/node_modules/@scope/mylib/package.json", `{"name": "@scope/mylib", "types": "index.d.ts"}`)
sys.writeFileNoError("/home/src/workspaces/project/node_modules/@scope/mylib/index.d.ts", `export declare const lib: string;`)
}),
},
},
{
subScenario: "watch detects package json types field edited",
files: FileMap{
"/home/src/workspaces/project/index.ts": `import { lib } from "mylib";`,
"/home/src/workspaces/project/tsconfig.json": `{}`,
"/home/src/workspaces/project/node_modules/mylib/package.json": `{"name": "mylib", "types": "old.d.ts"}`,
"/home/src/workspaces/project/node_modules/mylib/old.d.ts": `export declare const lib: number;`,
"/home/src/workspaces/project/node_modules/mylib/new.d.ts": `export declare const lib: string;`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("change package.json types field", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/node_modules/mylib/package.json", `{"name": "mylib", "types": "new.d.ts"}`)
}),
},
},
{
subScenario: "watch detects at-types package installed later",
files: FileMap{
"/home/src/workspaces/project/index.ts": `import * as lib from "untyped-lib";`,
"/home/src/workspaces/project/tsconfig.json": `{}`,
"/home/src/workspaces/project/node_modules/untyped-lib/index.js": `module.exports = {};`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("install @types for the library", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/node_modules/@types/untyped-lib/index.d.ts", `declare module "untyped-lib" { export const value: string; }`)
sys.writeFileNoError("/home/src/workspaces/project/node_modules/@types/untyped-lib/package.json", `{"name": "@types/untyped-lib", "types": "index.d.ts"}`)
}),
},
},
// File operations
{
subScenario: "watch detects file renamed and renamed back",
files: FileMap{
"/home/src/workspaces/project/index.ts": `import { helper } from "./helper";`,
"/home/src/workspaces/project/helper.ts": `export const helper = 1;`,
"/home/src/workspaces/project/tsconfig.json": `{}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
{
caption: "rename helper to helper2",
edit: func(sys *TestSys) {
sys.renameFileNoError("/home/src/workspaces/project/helper.ts", "/home/src/workspaces/project/helper2.ts")
},
expectedDiff: "incremental resolves to .js output from prior build while clean build cannot find module",
},
newTscEdit("rename back to helper", func(sys *TestSys) {
sys.renameFileNoError("/home/src/workspaces/project/helper2.ts", "/home/src/workspaces/project/helper.ts")
}),
},
},
{
subScenario: "watch detects file deleted and new file added simultaneously",
files: FileMap{
"/home/src/workspaces/project/a.ts": `import { b } from "./b";`,
"/home/src/workspaces/project/b.ts": `export const b = 1;`,
"/home/src/workspaces/project/tsconfig.json": `{}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("delete b.ts and create c.ts with updated import", func(sys *TestSys) {
sys.removeNoError("/home/src/workspaces/project/b.ts")
sys.writeFileNoError("/home/src/workspaces/project/c.ts", `export const c = 2;`)
sys.writeFileNoError("/home/src/workspaces/project/a.ts", `import { c } from "./c";`)
}),
},
},
{
subScenario: "watch handles file rapidly recreated",
files: FileMap{
"/home/src/workspaces/project/index.ts": `import { val } from "./data";`,
"/home/src/workspaces/project/data.ts": `export const val = "original";`,
"/home/src/workspaces/project/tsconfig.json": `{}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("delete and immediately recreate with new content", func(sys *TestSys) {
sys.removeNoError("/home/src/workspaces/project/data.ts")
sys.writeFileNoError("/home/src/workspaces/project/data.ts", `export const val = "recreated";`)
}),
},
},
// Symlinks — only node_modules symlinks are resolved via Realpath,
// matching the TypeScript compiler's behavior (see program.ts:2119).
{
subScenario: "watch detects change in symlinked node_modules file",
files: FileMap{
"/home/src/workspaces/project/index.ts": `import { shared } from "shared";`,
"/home/src/workspaces/shared/index.ts": `export const shared = "v1";`,
"/home/src/workspaces/project/node_modules/shared/index.ts": vfstest.Symlink("/home/src/workspaces/shared/index.ts"),
"/home/src/workspaces/project/tsconfig.json": `{}`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("modify symlink target", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/shared/index.ts", `export const shared = "v2";`)
}),
},
},
// Ancestor fallback stability — when a tsconfig include references a
// directory that doesn't exist
{
subScenario: "watch stability with ancestor directory fallback",
files: FileMap{
"/home/src/workspaces/project/index.ts": `const x: number = 1;`,
"/home/src/workspaces/project/tsconfig.json": `{ "include": ["*.ts", "missing/**/*"] }`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("trivial file change", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/index.ts", `const x: number = 2;`)
}),
},
},
// Ancestor fallback: creating deeply nested directories that didn't
// exist at initial build time should trigger a rebuild and re-watch.
{
subScenario: "watch detects file added in deeply nested non-existent include path",
files: FileMap{
"/home/src/workspaces/project/index.ts": `const x: number = 1;`,
"/home/src/workspaces/project/tsconfig.json": `{ "include": ["*.ts", "deep/nested/dir/**/*"] }`,
},
commandLineArgs: []string{"--watch"},
edits: []*tscEdit{
newTscEdit("create deeply nested file matching include", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/deep/nested/dir/added.ts", `export const added = 1;`)
}),
},
},
}
for _, test := range testCases {
test.run(t, "commandLineWatch")
}
}
func listToTsconfig(base string, tsconfigOpts ...string) (string, string) {
optionString := strings.Join(tsconfigOpts, ",\n ")
tsconfigText := `{
"compilerOptions": {
`
after := " "
if base != "" {
tsconfigText += " " + base
after = ",\n "
}
if len(tsconfigOpts) != 0 {
tsconfigText += after + optionString
}
tsconfigText += `
}
}`
return tsconfigText, optionString
}
func toTsconfig(base string, compilerOpts string) string {
tsconfigText, _ := listToTsconfig(base, compilerOpts)
return tsconfigText
}
func noEmitWatchTestInput(
subScenario string,
commandLineArgs []string,
aText string,
tsconfigOptions []string,
) *tscInput {
noEmitOpt := `"noEmit": true`
tsconfigText, optionString := listToTsconfig(noEmitOpt, tsconfigOptions...)
return &tscInput{
subScenario: subScenario,
commandLineArgs: commandLineArgs,
files: FileMap{
"/home/src/workspaces/project/a.ts": aText,
"/home/src/workspaces/project/tsconfig.json": tsconfigText,
},
edits: []*tscEdit{
newTscEdit("fix error", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/a.ts", `const a = "hello";`)
}),
newTscEdit("emit after fixing error", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/tsconfig.json", toTsconfig("", optionString))
}),
newTscEdit("no emit run after fixing error", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/tsconfig.json", toTsconfig(noEmitOpt, optionString))
}),
newTscEdit("introduce error", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/a.ts", aText)
}),
newTscEdit("emit when error", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/tsconfig.json", toTsconfig("", optionString))
}),
newTscEdit("no emit run when error", func(sys *TestSys) {
sys.writeFileNoError("/home/src/workspaces/project/tsconfig.json", toTsconfig(noEmitOpt, optionString))
}),
},
}
}
func newTscEdit(name string, edit func(sys *TestSys)) *tscEdit {
return &tscEdit{caption: name, edit: edit}
}
func TestTscNoEmitWatch(t *testing.T) {
t.Parallel()
testCases := []*tscInput{
noEmitWatchTestInput(
"syntax errors",
[]string{"-w"},
`const a = "hello`,
nil,
),
noEmitWatchTestInput(
"semantic errors",
[]string{"-w"},
`const a: number = "hello"`,
nil,
),
noEmitWatchTestInput(
"dts errors without dts enabled",
[]string{"-w"},
`const a = class { private p = 10; };`,
nil,
),
noEmitWatchTestInput(
"dts errors",
[]string{"-w"},
`const a = class { private p = 10; };`,
[]string{`"declaration": true`},
),
}
for _, test := range testCases {
test.run(t, "noEmit")
}
}