Skip to content

Commit 214d145

Browse files
Create comprehensive TypeScript test writing guide for Copilot
Co-authored-by: RyanCavanaugh <[email protected]>
1 parent a6c2ed7 commit 214d145

1 file changed

Lines changed: 259 additions & 0 deletions

File tree

.github/copilot-instructions.md

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
# TypeScript Test Writing Guide for Copilot
2+
3+
This document provides a concise guide for writing TypeScript fourslash tests and compiler tests, along with build instructions.
4+
5+
## Build Instructions Summary
6+
7+
### Setup
8+
1. Install Node.js (current or LTS)
9+
2. Install hereby: `npm install -g hereby`
10+
3. Clone the repository: `git clone --depth=1 https://github.com/microsoft/TypeScript`
11+
4. Install dependencies: `npm ci`
12+
13+
### Common Build Tasks
14+
```bash
15+
hereby local # Build the compiler into built/local
16+
hereby clean # Delete the built compiler
17+
hereby tests # Build the test infrastructure
18+
hereby runtests # Run all tests
19+
hereby runtests-parallel # Run tests in parallel (recommended)
20+
hereby runtests --runner=fourslash # Run only fourslash tests
21+
hereby runtests --runner=compiler # Run only compiler tests
22+
hereby runtests --tests=<testPath> # Run specific test
23+
hereby baseline-accept # Accept new test baselines
24+
hereby lint # Run eslint
25+
```
26+
27+
## Fourslash Test Syntax Guide
28+
29+
Fourslash tests are interactive TypeScript language service tests. They validate IDE features like completions, quick info, navigation, and refactoring.
30+
31+
### Basic Structure
32+
```typescript
33+
/// <reference path='fourslash.ts'/>
34+
35+
////code goes here with /*markers*/
36+
37+
// Test assertions go here
38+
```
39+
40+
### Key Syntax Elements
41+
42+
#### 1. Source Code Definition
43+
Use `////` to define source code lines:
44+
```typescript
45+
////function foo(x: number) {
46+
//// return x + 1;
47+
////}
48+
////let result = foo(/*marker*/42);
49+
```
50+
51+
#### 2. Markers for Positioning
52+
Use `/**/` for anonymous markers or `/*name*/` for named markers:
53+
```typescript
54+
////let x = /*1*/someValue;
55+
////let y = /*cursor*/anotherValue;
56+
```
57+
58+
#### 3. Multi-file Tests
59+
Use `// @Filename:` to define multiple files:
60+
```typescript
61+
// @Filename: /a.ts
62+
////export const value = 42;
63+
64+
// @Filename: /b.ts
65+
////import { value } from './a';
66+
////console.log(/*marker*/value);
67+
```
68+
69+
#### 4. Ranges
70+
Use `[|text|]` to define text ranges:
71+
```typescript
72+
////function test() {
73+
//// [|return 42;|]
74+
////}
75+
```
76+
77+
### Common API Patterns
78+
79+
#### Navigation & Positioning
80+
```typescript
81+
goTo.marker("markerName"); // Navigate to marker
82+
goTo.marker(); // Navigate to anonymous marker /**/
83+
```
84+
85+
#### Verification (Prefer these over baselines)
86+
```typescript
87+
verify.currentLineContentIs("expected content");
88+
verify.completions({ includes: "itemName" });
89+
verify.completions({ excludes: "itemName" });
90+
verify.quickInfoIs("expected info");
91+
verify.codeFix({
92+
description: "Fix description",
93+
newFileContent: "expected content after fix"
94+
});
95+
```
96+
97+
#### Completions Testing
98+
```typescript
99+
verify.completions({
100+
marker: "1",
101+
includes: { name: "foo", source: "/a", hasAction: true },
102+
isNewIdentifierLocation: true,
103+
preferences: { includeCompletionsForModuleExports: true }
104+
});
105+
```
106+
107+
#### Code Fixes Testing
108+
```typescript
109+
verify.codeFix({
110+
description: "Add missing property",
111+
index: 0,
112+
newFileContent: `class C {
113+
property: string;
114+
method() { this.property = "value"; }
115+
}`
116+
});
117+
```
118+
119+
#### Formatting
120+
```typescript
121+
format.document();
122+
verify.currentLineContentIs("formatted content");
123+
```
124+
125+
### Simple Example
126+
```typescript
127+
/// <reference path='fourslash.ts'/>
128+
129+
////interface User {
130+
//// name: string;
131+
////}
132+
////
133+
////const user: User = {
134+
//// /*completion*/
135+
////};
136+
137+
verify.completions({
138+
marker: "completion",
139+
includes: { name: "name", sortText: "0" }
140+
});
141+
```
142+
143+
## Compiler Test Syntax Guide
144+
145+
Compiler tests validate TypeScript compilation behavior, type checking, and error reporting.
146+
147+
### Basic Structure
148+
- Simple `.ts` files in `tests/cases/compiler/`
149+
- Use comments to indicate expected behavior
150+
- No special test harness - just TypeScript code
151+
152+
### Compiler Directives
153+
Use `// @directive: value` for compiler options:
154+
```typescript
155+
// @strict: true
156+
// @target: ES2015
157+
// @lib: ES2015,DOM
158+
159+
let x: string = 42; // Error expected
160+
```
161+
162+
### Common Directives
163+
```typescript
164+
// @strict: true/false
165+
// @noImplicitAny: true/false
166+
// @target: ES5/ES2015/ES2020/ESNext
167+
// @module: commonjs/amd/es6/esnext
168+
// @lib: ES5,DOM/ES2015/ES2020
169+
// @declaration: true/false
170+
// @skipLibCheck: true/false
171+
```
172+
173+
### Multi-file Tests
174+
```typescript
175+
// @Filename: helper.ts
176+
export function helper(x: number): string {
177+
return x.toString();
178+
}
179+
180+
// @Filename: main.ts
181+
import { helper } from "./helper";
182+
const result = helper(42);
183+
```
184+
185+
### Error Expectations
186+
Use comments to document expected behavior:
187+
```typescript
188+
abstract class Base {
189+
abstract method(): void;
190+
}
191+
192+
class Derived extends Base {
193+
// Missing implementation - should error
194+
}
195+
196+
new Base(); // Should error - cannot instantiate abstract class
197+
```
198+
199+
### Type Testing Patterns
200+
```typescript
201+
// Test type inference
202+
let inferred = [1, 2, 3]; // Should infer number[]
203+
204+
// Test type compatibility
205+
type A = { x: number };
206+
type B = { x: number; y: string };
207+
let a: A = { x: 1 };
208+
let b: B = { x: 1, y: "hello" };
209+
a = b; // Should work - B is assignable to A
210+
b = a; // Should error - A missing property y
211+
```
212+
213+
### Simple Example
214+
```typescript
215+
// Test that optional properties work correctly
216+
interface Config {
217+
required: string;
218+
optional?: number;
219+
}
220+
221+
const config1: Config = { required: "test" }; // Should work
222+
const config2: Config = { required: "test", optional: 42 }; // Should work
223+
const config3: Config = { optional: 42 }; // Should error - missing required
224+
```
225+
226+
## Test Writing Best Practices
227+
228+
### For Fourslash Tests
229+
1. **Prefer validation over baselines** - Use `verify.currentLineContentIs()` instead of `verify.baseline*()`
230+
2. **Use simple, focused examples** - Test one feature at a time
231+
3. **Name markers clearly** - Use descriptive marker names like `/*completion*/`
232+
4. **Test the simplest form first** - Start with basic cases before complex scenarios
233+
234+
### For Compiler Tests
235+
1. **Use clear file names** - Name tests after the feature being tested
236+
2. **Add explanatory comments** - Document expected behavior with comments
237+
3. **Test error cases** - Include both valid and invalid code examples
238+
4. **Keep tests focused** - One primary feature per test file
239+
240+
### General Guidelines
241+
1. **Make tests deterministic** - Avoid random or environment-dependent behavior
242+
2. **Use realistic examples** - Test scenarios developers actually encounter
243+
3. **Start simple** - Begin with the most basic case of a feature
244+
4. **Test edge cases** - Include boundary conditions and error scenarios
245+
246+
## Running Specific Tests
247+
248+
```bash
249+
# Run a specific fourslash test
250+
hereby runtests --tests=tests/cases/fourslash/completionForObjectProperty.ts
251+
252+
# Run a specific compiler test
253+
hereby runtests --tests=tests/cases/compiler/abstractClassUnionInstantiation.ts
254+
255+
# Run tests matching a pattern
256+
hereby runtests --tests=tests/cases/fourslash/completion*.ts
257+
```
258+
259+
This guide focuses on the most common and idiomatic patterns for writing TypeScript tests. For complex scenarios, refer to existing tests in the codebase for additional patterns and techniques.

0 commit comments

Comments
 (0)