• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

source-academy / js-slang / 23995741899

05 Apr 2026 06:14AM UTC coverage: 77.093% (+0.002%) from 77.091%
23995741899

push

github

web-flow
Upgrade to TypeScript 6 and Prettier improvements (#1936)

* Upgrade TypeScript to v6

* Fix import source

* Fix tsconfig

* Fix preexisting type errors

* Remove scm-slang

* Bump node types

* Fix tsconfig

* Fix node types specifier

* Enable trailing commas

* Enable semicolons

* Check and commit files with changed line numbers

* Update Yarn to 4.13.0

* Remove unneeded sicp package deps

3112 of 4282 branches covered (72.68%)

Branch coverage included in aggregate %.

3761 of 5218 new or added lines in 152 files covered. (72.08%)

26 existing lines in 9 files now uncovered.

7136 of 9011 relevant lines covered (79.19%)

175254.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.67
/src/utils/testing/misc.ts
1
import { describe, expect, test, type TestContext as VitestTestContext } from 'vitest';
2
import type { Result } from '../..';
3
import { Chapter } from '../../langs';
4
import type { Finished, Node, NodeTypeToNode, Value } from '../../types';
5
import { getChapterName } from '../misc';
6
import type { TestBuiltins, TestOptions } from './types';
7

8
/**
9
 * Convert the options provided by the user for each test into the full options
10
 * used by the testing system
11
 */
12
export function processTestOptions(rawOptions: TestOptions): Exclude<TestOptions, Chapter> {
13
  return typeof rawOptions === 'number'
752✔
14
    ? {
15
        chapter: rawOptions,
16
      }
17
    : rawOptions;
18
}
19

20
/**
21
 * Utility type for removing the `this` parameter from a function's type
22
 */
23
type RemoveThis<T extends (this: any, ...args: any[]) => any> = T extends (
24
  this: any,
25
  ...args: infer U
26
) => any
27
  ? U
28
  : Parameters<T>;
29

30
interface FuncWithSkipAndOnly<T extends (...args: any[]) => any> {
31
  (...args: RemoveThis<T>): ReturnType<T>;
32
  skip: (...args: RemoveThis<T>) => ReturnType<T>;
33
  only: (...args: RemoveThis<T>) => ReturnType<T>;
34
}
35

36
/**
37
 * Refers to the three `describe` operations
38
 */
39
export type DescribeFunctions =
40
  | typeof describe
41
  | (typeof describe)['only']
42
  | (typeof describe)['skip'];
43

44
/**
45
 * Refers to the three `test` operations
46
 */
47
export type TestFunctions = typeof test | (typeof test)['only'] | (typeof test)['skip'];
48

49
/**
50
 * For functions that are designed to wrap around a `describe` or `test` block. Adds the `.only` and `.skip`
51
 * properties to them. The wrapped functions should use the `this` object to access the `test` or `describe` function
52
 * they are supposed to call.
53
 */
54
export function wrapWithSkipAndOnly<T extends (this: DescribeFunctions, ...args: any[]) => any>(
55
  type: 'describe',
56
  f: T,
57
): FuncWithSkipAndOnly<T>;
58
export function wrapWithSkipAndOnly<T extends (this: TestFunctions, ...args: any[]) => any>(
59
  type: 'test',
60
  f: T,
61
): FuncWithSkipAndOnly<T>;
62
export function wrapWithSkipAndOnly<
63
  T extends (this: TestFunctions | DescribeFunctions, ...args: any[]) => any,
64
>(type: 'test' | 'describe', f: T) {
65
  function func(...args: Parameters<T>): ReturnType<T> {
66
    return f.call(type === 'test' ? test : describe, ...args);
6!
67
  }
68

69
  func.skip = (...args: Parameters<T>) => {
31✔
NEW
70
    return f.call((type === 'test' ? test : describe).skip, ...args);
×
71
  };
72

73
  func.only = (...args: Parameters<T>) => {
31✔
NEW
74
    return f.call((type === 'test' ? test : describe).only, ...args);
×
75
  };
76

77
  return func as FuncWithSkipAndOnly<T>;
31✔
78
}
79

80
/**
81
 * Asserts that the given value is true
82
 */
83
export function assertTruthy(cond: boolean): asserts cond {
84
  expect(cond).toBeTruthy();
18✔
85
}
86

87
/**
88
 * Convenience wrapper for testing multiple cases with the same
89
 * test function
90
 */
91
export const testMultipleCases = wrapWithSkipAndOnly('test', function <
30✔
92
  T extends Array<any>,
93
>(this: TestFunctions, cases: [string, ...T][], tester: (args: T, i: number) => void | Promise<void>, includeIndex?: boolean, timeout?: number) {
94
  const withIndex = cases.map(([desc, ...c], i) => {
×
NEW
95
    const newDesc = includeIndex ? `${i + 1}. ${desc}` : desc;
×
NEW
96
    return [newDesc, i, ...c] as [string, number, ...T];
×
97
  });
NEW
98
  this.each(withIndex)('%s', (_, i, ...args) => tester(args, i), timeout);
×
99
});
100

101
type ChapterTestingFunction = (
102
  chapter: Chapter,
103
  context: VitestTestContext,
104
) => void | Promise<void>;
105

106
/**
107
 * Convenience wrapper for testing a case with multiple chapters. Tests with source chapters 1-4 and the library parser
108
 */
109
export function testWithChapters(func: ChapterTestingFunction): void;
110

111
/**
112
 * Convenience wrapper for testing a case with multiple chapters. Tests with the given chapters. Returns a function
113
 * that should be called in the same way `test.each` is
114
 */
115
export function testWithChapters(...chapters: Chapter[]): (f: ChapterTestingFunction) => void;
116
export function testWithChapters(arg0: ChapterTestingFunction | Chapter, ...chapters: Chapter[]) {
117
  const tester = (chapters: Chapter[], func: ChapterTestingFunction) =>
10✔
118
    test.for(chapters.map(chapter => [getChapterName(chapter), chapter] as [string, Chapter]))(
34✔
119
      'Testing %s',
120
      ([, chapter], context) => func(chapter, context),
34✔
121
    );
122

123
  if (typeof arg0 === 'function') {
10✔
124
    return tester(
1✔
125
      [
126
        Chapter.SOURCE_1,
127
        Chapter.SOURCE_2,
128
        Chapter.SOURCE_3,
129
        Chapter.SOURCE_4,
130
        Chapter.LIBRARY_PARSER,
131
      ],
132
      arg0,
133
    );
134
  }
135

136
  return (func: ChapterTestingFunction) => tester([arg0, ...chapters], func);
9✔
137
}
138

139
/**
140
 * Asserts that the provided result is a `Finished`
141
 */
142
export function assertIsFinished(result: Result): asserts result is Finished {
143
  expect(result.status).toEqual('finished');
455✔
144
}
145

146
/**
147
 * Asserts that the provided result is both `Finished` and is equal to the given value
148
 */
149
export function assertFinishedResultValue(result: Result, value: Value) {
150
  assertIsFinished(result);
13✔
151
  expect(result.value).toEqual(value);
13✔
152
}
153

154
/**
155
 * Type safe assertion. Expects the given Node to have the provided type
156
 */
157
export function assertNodeType<T extends Node['type']>(
158
  typeStr: T,
159
  node: Node,
160
): asserts node is NodeTypeToNode<T> {
161
  expect(node.type).toEqual(typeStr);
2✔
162
}
163

164
/**
165
 * Calls `eval` on the provided code with the provided builtins
166
 */
167
export function evalWithBuiltins(code: string, testBuiltins: TestBuiltins = {}) {
16✔
168
  // Ugly, but if you know how to `eval` code with some builtins attached, please change this.
169
  const builtins = Object.keys(testBuiltins).map(key => `const ${key} = testBuiltins.${key};`);
16✔
170
  const evalstring = builtins.join('\n') + code;
16✔
171

172
  return eval(evalstring + code);
16✔
173
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc