@sharpee/transcript-tester 0.9.61-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +4 -0
- package/LICENSE +21 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +367 -0
- package/dist/cli.js.map +1 -0
- package/dist/condition-evaluator.d.ts +30 -0
- package/dist/condition-evaluator.d.ts.map +1 -0
- package/dist/condition-evaluator.js +314 -0
- package/dist/condition-evaluator.js.map +1 -0
- package/dist/fast-cli.d.ts +13 -0
- package/dist/fast-cli.d.ts.map +1 -0
- package/dist/fast-cli.js +363 -0
- package/dist/fast-cli.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/navigator.d.ts +27 -0
- package/dist/navigator.d.ts.map +1 -0
- package/dist/navigator.js +303 -0
- package/dist/navigator.js.map +1 -0
- package/dist/parser.d.ts +19 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +453 -0
- package/dist/parser.js.map +1 -0
- package/dist/reporter.d.ts +41 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +386 -0
- package/dist/reporter.js.map +1 -0
- package/dist/runner.d.ts +44 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +977 -0
- package/dist/runner.js.map +1 -0
- package/dist/story-loader.d.ts +31 -0
- package/dist/story-loader.d.ts.map +1 -0
- package/dist/story-loader.js +169 -0
- package/dist/story-loader.js.map +1 -0
- package/dist/types.d.ts +204 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist-esm/cli.d.ts +11 -0
- package/dist-esm/cli.d.ts.map +1 -0
- package/dist-esm/cli.js +332 -0
- package/dist-esm/cli.js.map +1 -0
- package/dist-esm/condition-evaluator.d.ts +30 -0
- package/dist-esm/condition-evaluator.d.ts.map +1 -0
- package/dist-esm/condition-evaluator.js +311 -0
- package/dist-esm/condition-evaluator.js.map +1 -0
- package/dist-esm/fast-cli.d.ts +13 -0
- package/dist-esm/fast-cli.d.ts.map +1 -0
- package/dist-esm/fast-cli.js +328 -0
- package/dist-esm/fast-cli.js.map +1 -0
- package/dist-esm/index.d.ts +17 -0
- package/dist-esm/index.d.ts.map +1 -0
- package/dist-esm/index.js +21 -0
- package/dist-esm/index.js.map +1 -0
- package/dist-esm/navigator.d.ts +27 -0
- package/dist-esm/navigator.d.ts.map +1 -0
- package/dist-esm/navigator.js +300 -0
- package/dist-esm/navigator.js.map +1 -0
- package/dist-esm/parser.d.ts +19 -0
- package/dist-esm/parser.d.ts.map +1 -0
- package/dist-esm/parser.js +415 -0
- package/dist-esm/parser.js.map +1 -0
- package/dist-esm/reporter.d.ts +41 -0
- package/dist-esm/reporter.d.ts.map +1 -0
- package/dist-esm/reporter.js +342 -0
- package/dist-esm/reporter.js.map +1 -0
- package/dist-esm/runner.d.ts +44 -0
- package/dist-esm/runner.d.ts.map +1 -0
- package/dist-esm/runner.js +941 -0
- package/dist-esm/runner.js.map +1 -0
- package/dist-esm/story-loader.d.ts +31 -0
- package/dist-esm/story-loader.d.ts.map +1 -0
- package/dist-esm/story-loader.js +131 -0
- package/dist-esm/story-loader.js.map +1 -0
- package/dist-esm/types.d.ts +204 -0
- package/dist-esm/types.d.ts.map +1 -0
- package/dist-esm/types.js +7 -0
- package/dist-esm/types.js.map +1 -0
- package/dist-npm/cli.d.ts +11 -0
- package/dist-npm/cli.d.ts.map +1 -0
- package/dist-npm/cli.js +367 -0
- package/dist-npm/cli.js.map +1 -0
- package/dist-npm/condition-evaluator.d.ts +30 -0
- package/dist-npm/condition-evaluator.d.ts.map +1 -0
- package/dist-npm/condition-evaluator.js +314 -0
- package/dist-npm/condition-evaluator.js.map +1 -0
- package/dist-npm/fast-cli.d.ts +13 -0
- package/dist-npm/fast-cli.d.ts.map +1 -0
- package/dist-npm/fast-cli.js +363 -0
- package/dist-npm/fast-cli.js.map +1 -0
- package/dist-npm/index.d.ts +17 -0
- package/dist-npm/index.d.ts.map +1 -0
- package/dist-npm/index.js +48 -0
- package/dist-npm/index.js.map +1 -0
- package/dist-npm/navigator.d.ts +27 -0
- package/dist-npm/navigator.d.ts.map +1 -0
- package/dist-npm/navigator.js +303 -0
- package/dist-npm/navigator.js.map +1 -0
- package/dist-npm/parser.d.ts +19 -0
- package/dist-npm/parser.d.ts.map +1 -0
- package/dist-npm/parser.js +453 -0
- package/dist-npm/parser.js.map +1 -0
- package/dist-npm/reporter.d.ts +41 -0
- package/dist-npm/reporter.d.ts.map +1 -0
- package/dist-npm/reporter.js +386 -0
- package/dist-npm/reporter.js.map +1 -0
- package/dist-npm/runner.d.ts +44 -0
- package/dist-npm/runner.d.ts.map +1 -0
- package/dist-npm/runner.js +977 -0
- package/dist-npm/runner.js.map +1 -0
- package/dist-npm/story-loader.d.ts +31 -0
- package/dist-npm/story-loader.d.ts.map +1 -0
- package/dist-npm/story-loader.js +169 -0
- package/dist-npm/story-loader.js.map +1 -0
- package/dist-npm/types.d.ts +204 -0
- package/dist-npm/types.d.ts.map +1 -0
- package/dist-npm/types.js +8 -0
- package/dist-npm/types.js.map +1 -0
- package/package.json +49 -0
- package/src/cli.ts +385 -0
- package/src/condition-evaluator.ts +382 -0
- package/src/fast-cli.ts +403 -0
- package/src/index.ts +26 -0
- package/src/navigator.ts +365 -0
- package/src/parser.ts +488 -0
- package/src/reporter.ts +409 -0
- package/src/runner.ts +1152 -0
- package/src/story-loader.ts +168 -0
- package/src/types.ts +244 -0
- package/tsconfig.esm.json +11 -0
- package/tsconfig.esm.tsbuildinfo +1 -0
- package/tsconfig.json +22 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story Loader
|
|
3
|
+
*
|
|
4
|
+
* Dynamically loads and initializes a story for testing.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import { GameEngine, TurnResult, SequencedEvent } from '@sharpee/engine';
|
|
9
|
+
import { WorldModel, EntityType } from '@sharpee/world-model';
|
|
10
|
+
import { Parser } from '@sharpee/parser-en-us';
|
|
11
|
+
import { PerceptionService } from '@sharpee/stdlib';
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
import { LanguageProvider } from '@sharpee/lang-en-us';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Interface for a story module
|
|
17
|
+
*/
|
|
18
|
+
interface StoryModule {
|
|
19
|
+
story?: any;
|
|
20
|
+
default?: any;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A testable game instance
|
|
25
|
+
*/
|
|
26
|
+
export interface TestableGame {
|
|
27
|
+
engine: GameEngine;
|
|
28
|
+
world: WorldModel;
|
|
29
|
+
lastOutput: string;
|
|
30
|
+
lastEvents: SequencedEvent[];
|
|
31
|
+
lastTurnResult: TurnResult | null;
|
|
32
|
+
executeCommand(input: string): Promise<string>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Load a story from a path and create a testable game instance
|
|
37
|
+
*/
|
|
38
|
+
export async function loadStory(storyPath: string): Promise<TestableGame> {
|
|
39
|
+
// Resolve the story path
|
|
40
|
+
const resolvedPath = path.isAbsolute(storyPath)
|
|
41
|
+
? storyPath
|
|
42
|
+
: path.resolve(process.cwd(), storyPath);
|
|
43
|
+
|
|
44
|
+
// Try to load the story module
|
|
45
|
+
let storyModule: StoryModule;
|
|
46
|
+
try {
|
|
47
|
+
// Try loading the compiled dist version first
|
|
48
|
+
const distPath = path.join(resolvedPath, 'dist', 'index.js');
|
|
49
|
+
storyModule = require(distPath);
|
|
50
|
+
} catch (e) {
|
|
51
|
+
try {
|
|
52
|
+
// Fall back to src (for ts-node environments)
|
|
53
|
+
const srcPath = path.join(resolvedPath, 'src', 'index.ts');
|
|
54
|
+
storyModule = require(srcPath);
|
|
55
|
+
} catch (e2) {
|
|
56
|
+
throw new Error(`Could not load story from ${storyPath}: ${e}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const story = storyModule.story || storyModule.default;
|
|
61
|
+
if (!story) {
|
|
62
|
+
throw new Error(`Story module at ${storyPath} does not export 'story' or 'default'`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Create the game instance
|
|
66
|
+
return createTestableGame(story);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Create a testable game from a story instance
|
|
71
|
+
*/
|
|
72
|
+
export function createTestableGame(story: any): TestableGame {
|
|
73
|
+
// Create world and player
|
|
74
|
+
const world = new WorldModel();
|
|
75
|
+
const player = world.createEntity('player', EntityType.ACTOR);
|
|
76
|
+
world.setPlayer(player.id);
|
|
77
|
+
|
|
78
|
+
// Create parser and language
|
|
79
|
+
const language = new LanguageProvider();
|
|
80
|
+
const parser = new Parser(language);
|
|
81
|
+
|
|
82
|
+
// Extend parser and language with story-specific vocabulary
|
|
83
|
+
if (story.extendParser) {
|
|
84
|
+
story.extendParser(parser);
|
|
85
|
+
}
|
|
86
|
+
if (story.extendLanguage) {
|
|
87
|
+
story.extendLanguage(language);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Create perception service
|
|
91
|
+
const perceptionService = new PerceptionService();
|
|
92
|
+
|
|
93
|
+
// Create engine (TextService created internally from language provider)
|
|
94
|
+
const engine = new GameEngine({
|
|
95
|
+
world,
|
|
96
|
+
player,
|
|
97
|
+
parser,
|
|
98
|
+
language,
|
|
99
|
+
perceptionService,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Set the story and start
|
|
103
|
+
engine.setStory(story);
|
|
104
|
+
engine.start();
|
|
105
|
+
|
|
106
|
+
// Capture text output and events
|
|
107
|
+
let lastOutput = '';
|
|
108
|
+
let outputBuffer: string[] = [];
|
|
109
|
+
let lastEvents: SequencedEvent[] = [];
|
|
110
|
+
let lastTurnResult: TurnResult | null = null;
|
|
111
|
+
|
|
112
|
+
engine.on('text:output', (text: string) => {
|
|
113
|
+
outputBuffer.push(text);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Capture ALL events through the event emitter (includes scheduler/NPC events)
|
|
117
|
+
let eventBuffer: SequencedEvent[] = [];
|
|
118
|
+
engine.on('event', (event: SequencedEvent) => {
|
|
119
|
+
eventBuffer.push(event);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Create the testable game interface
|
|
123
|
+
const testableGame: TestableGame = {
|
|
124
|
+
engine,
|
|
125
|
+
world,
|
|
126
|
+
lastOutput: '',
|
|
127
|
+
lastEvents: [],
|
|
128
|
+
lastTurnResult: null,
|
|
129
|
+
|
|
130
|
+
async executeCommand(input: string): Promise<string> {
|
|
131
|
+
outputBuffer = [];
|
|
132
|
+
eventBuffer = []; // Reset event buffer for this command
|
|
133
|
+
lastEvents = [];
|
|
134
|
+
lastTurnResult = null;
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const result = await engine.executeTurn(input);
|
|
138
|
+
if (result) {
|
|
139
|
+
lastTurnResult = result;
|
|
140
|
+
// Use eventBuffer which captures ALL events (action + NPC + scheduler)
|
|
141
|
+
lastEvents = eventBuffer;
|
|
142
|
+
}
|
|
143
|
+
} catch (error) {
|
|
144
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
145
|
+
outputBuffer.push(`Error: ${errorMessage}`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
lastOutput = outputBuffer.join('\n');
|
|
149
|
+
testableGame.lastOutput = lastOutput;
|
|
150
|
+
testableGame.lastEvents = lastEvents;
|
|
151
|
+
testableGame.lastTurnResult = lastTurnResult;
|
|
152
|
+
return lastOutput;
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
return testableGame;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Find all transcript files in a directory
|
|
161
|
+
*/
|
|
162
|
+
export function findTranscripts(dir: string, pattern: string = '*.transcript'): string[] {
|
|
163
|
+
const glob = require('glob');
|
|
164
|
+
const resolvedDir = path.isAbsolute(dir) ? dir : path.resolve(process.cwd(), dir);
|
|
165
|
+
|
|
166
|
+
const files = glob.sync(path.join(resolvedDir, '**', pattern));
|
|
167
|
+
return files;
|
|
168
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transcript Testing Types
|
|
3
|
+
*
|
|
4
|
+
* Defines the structure of parsed transcripts and test results.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Directive Types (ADR-092: Smart Transcript Directives)
|
|
9
|
+
// ============================================================================
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Types of control flow directives
|
|
13
|
+
*/
|
|
14
|
+
export type DirectiveType =
|
|
15
|
+
| 'goal' // [GOAL: name]
|
|
16
|
+
| 'end_goal' // [END GOAL]
|
|
17
|
+
| 'requires' // [REQUIRES: condition]
|
|
18
|
+
| 'ensures' // [ENSURES: condition]
|
|
19
|
+
| 'if' // [IF: condition]
|
|
20
|
+
| 'end_if' // [END IF]
|
|
21
|
+
| 'while' // [WHILE: condition]
|
|
22
|
+
| 'end_while' // [END WHILE]
|
|
23
|
+
| 'navigate' // [NAVIGATE TO: "Room Name"]
|
|
24
|
+
| 'save' // $save <name>
|
|
25
|
+
| 'restore' // $restore <name>
|
|
26
|
+
| 'test-command'; // $teleport, $take, $kill, etc. (ext-testing)
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A control flow directive in the transcript
|
|
30
|
+
*/
|
|
31
|
+
export interface Directive {
|
|
32
|
+
type: DirectiveType;
|
|
33
|
+
lineNumber: number;
|
|
34
|
+
condition?: string; // For IF/WHILE/REQUIRES/ENSURES: the condition expression
|
|
35
|
+
target?: string; // For NAVIGATE: the target room name
|
|
36
|
+
goalName?: string; // For GOAL: the goal name
|
|
37
|
+
saveName?: string; // For SAVE/RESTORE: the checkpoint name
|
|
38
|
+
testCommand?: string; // For test-command: the full $command input (e.g., "$teleport kitchen")
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* A goal segment with its preconditions, postconditions, and content
|
|
43
|
+
*/
|
|
44
|
+
export interface GoalDefinition {
|
|
45
|
+
name: string;
|
|
46
|
+
lineNumber: number;
|
|
47
|
+
requires: string[]; // Precondition expressions
|
|
48
|
+
ensures: string[]; // Postcondition expressions
|
|
49
|
+
startIndex: number; // Index in items array where goal content starts
|
|
50
|
+
endIndex: number; // Index in items array where goal ends
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Result of executing a goal
|
|
55
|
+
*/
|
|
56
|
+
export interface GoalResult {
|
|
57
|
+
name: string;
|
|
58
|
+
success: boolean;
|
|
59
|
+
requiresResults: ConditionResult[];
|
|
60
|
+
ensuresResults: ConditionResult[];
|
|
61
|
+
commandsExecuted: number;
|
|
62
|
+
error?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Result of evaluating a condition
|
|
67
|
+
*/
|
|
68
|
+
export interface ConditionResult {
|
|
69
|
+
met: boolean;
|
|
70
|
+
reason: string; // Human-readable explanation
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Result of executing a NAVIGATE directive
|
|
75
|
+
*/
|
|
76
|
+
export interface NavigateResult {
|
|
77
|
+
success: boolean;
|
|
78
|
+
path: string[]; // Room names traversed
|
|
79
|
+
commands: string[]; // GO commands executed
|
|
80
|
+
error?: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* A comment annotation from the transcript (# lines)
|
|
85
|
+
*/
|
|
86
|
+
export interface TranscriptComment {
|
|
87
|
+
lineNumber: number;
|
|
88
|
+
text: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* A transcript item - either a command, directive, or comment
|
|
93
|
+
*/
|
|
94
|
+
export interface TranscriptItem {
|
|
95
|
+
type: 'command' | 'directive' | 'comment';
|
|
96
|
+
command?: TranscriptCommand;
|
|
97
|
+
directive?: Directive;
|
|
98
|
+
comment?: TranscriptComment;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ============================================================================
|
|
102
|
+
// Original Types
|
|
103
|
+
// ============================================================================
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Header metadata from a transcript file
|
|
107
|
+
*/
|
|
108
|
+
export interface TranscriptHeader {
|
|
109
|
+
title?: string;
|
|
110
|
+
story?: string;
|
|
111
|
+
author?: string;
|
|
112
|
+
description?: string;
|
|
113
|
+
[key: string]: string | undefined;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* A single assertion about command output, events, or state
|
|
118
|
+
*/
|
|
119
|
+
export interface Assertion {
|
|
120
|
+
type: 'ok' | 'ok-contains' | 'ok-matches' | 'ok-not-contains' | 'fail' | 'skip' | 'todo'
|
|
121
|
+
| 'event-count' | 'event-assert' | 'state-assert';
|
|
122
|
+
value?: string; // For contains/matches
|
|
123
|
+
pattern?: RegExp; // For regex matches
|
|
124
|
+
reason?: string; // For fail/todo
|
|
125
|
+
|
|
126
|
+
// Event assertions
|
|
127
|
+
eventCount?: number; // For event-count assertion
|
|
128
|
+
assertTrue?: boolean; // For event-assert and state-assert: true = must exist, false = must not exist
|
|
129
|
+
eventPosition?: number; // For event-assert: optional 1-based position (omit for "any position")
|
|
130
|
+
eventType?: string; // For event-assert: the event type to match
|
|
131
|
+
eventData?: Record<string, any>; // For event-assert: data properties to match
|
|
132
|
+
|
|
133
|
+
// State assertions
|
|
134
|
+
stateExpression?: string; // For state-assert: the expression to evaluate (e.g., "egg.location = thief")
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* A single command with its expected output and assertions
|
|
139
|
+
*/
|
|
140
|
+
export interface TranscriptCommand {
|
|
141
|
+
lineNumber: number;
|
|
142
|
+
input: string;
|
|
143
|
+
expectedOutput: string[];
|
|
144
|
+
assertions: Assertion[];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* A fully parsed transcript file
|
|
149
|
+
*/
|
|
150
|
+
export interface Transcript {
|
|
151
|
+
filePath: string;
|
|
152
|
+
header: TranscriptHeader;
|
|
153
|
+
commands: TranscriptCommand[]; // Legacy: just commands (for backwards compat)
|
|
154
|
+
items?: TranscriptItem[]; // New: commands + directives in order
|
|
155
|
+
goals?: GoalDefinition[]; // Parsed goal segments
|
|
156
|
+
comments: string[];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Simplified event info for test results
|
|
161
|
+
*/
|
|
162
|
+
export interface TestEventInfo {
|
|
163
|
+
type: string;
|
|
164
|
+
data: Record<string, any>;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Result of running a single command
|
|
169
|
+
*/
|
|
170
|
+
export interface CommandResult {
|
|
171
|
+
command: TranscriptCommand;
|
|
172
|
+
actualOutput: string;
|
|
173
|
+
actualEvents: TestEventInfo[];
|
|
174
|
+
passed: boolean;
|
|
175
|
+
expectedFailure: boolean; // Was marked [FAIL]
|
|
176
|
+
skipped: boolean; // Was marked [SKIP] or [TODO]
|
|
177
|
+
assertionResults: AssertionResult[];
|
|
178
|
+
error?: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Result of a single assertion check
|
|
183
|
+
*/
|
|
184
|
+
export interface AssertionResult {
|
|
185
|
+
assertion: Assertion;
|
|
186
|
+
passed: boolean;
|
|
187
|
+
message?: string;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Result of running an entire transcript
|
|
192
|
+
*/
|
|
193
|
+
export interface TranscriptResult {
|
|
194
|
+
transcript: Transcript;
|
|
195
|
+
commands: CommandResult[];
|
|
196
|
+
passed: number;
|
|
197
|
+
failed: number;
|
|
198
|
+
expectedFailures: number;
|
|
199
|
+
skipped: number;
|
|
200
|
+
duration: number; // milliseconds
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Result of running multiple transcripts
|
|
205
|
+
*/
|
|
206
|
+
export interface TestRunResult {
|
|
207
|
+
transcripts: TranscriptResult[];
|
|
208
|
+
totalPassed: number;
|
|
209
|
+
totalFailed: number;
|
|
210
|
+
totalExpectedFailures: number;
|
|
211
|
+
totalSkipped: number;
|
|
212
|
+
totalDuration: number;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Options for the test runner
|
|
217
|
+
*/
|
|
218
|
+
/**
|
|
219
|
+
* Interface for ext-testing extension (optional)
|
|
220
|
+
*/
|
|
221
|
+
export interface TestingExtensionInterface {
|
|
222
|
+
executeTestCommand(input: string, world: any): { success: boolean; output: string[]; error?: string };
|
|
223
|
+
/** Set context for annotation commands (called after each command execution) */
|
|
224
|
+
setCommandContext?(command: string, response: string): void;
|
|
225
|
+
/** Add an annotation directly (for # comments) */
|
|
226
|
+
addAnnotation?(type: string, text: string, world: any): any;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export interface RunnerOptions {
|
|
230
|
+
verbose?: boolean;
|
|
231
|
+
stopOnFailure?: boolean;
|
|
232
|
+
updateExpected?: boolean;
|
|
233
|
+
filter?: string; // Only run commands matching this pattern
|
|
234
|
+
savesDirectory?: string; // Directory for $save/$restore checkpoints
|
|
235
|
+
testingExtension?: TestingExtensionInterface; // Optional ext-testing integration
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Story loader function type
|
|
240
|
+
*/
|
|
241
|
+
export type StoryLoader = (storyPath: string) => Promise<{
|
|
242
|
+
engine: any; // GameEngine
|
|
243
|
+
story: any; // Story instance
|
|
244
|
+
}>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base-esm.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "./dist-esm",
|
|
5
|
+
"rootDir": "./src",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"declarationMap": true
|
|
8
|
+
},
|
|
9
|
+
"include": ["src/**/*"],
|
|
10
|
+
"exclude": ["node_modules", "dist", "dist-esm", "**/*.test.ts", "**/*.spec.ts"]
|
|
11
|
+
}
|