Skip to content

Commit de9546b

Browse files
TimothyJonesclaude
andauthored
refactor(plugin-dsl)!: Change describe type to return structured DescribeSegment instead of string. Plugin authors will need to use the new factory functions to implement their describe methods instead of returning a string. This allows structured rendering of the describe result (#1246)
Co-authored-by: Claude <noreply@anthropic.com>
1 parent eb29d66 commit de9546b

57 files changed

Lines changed: 1607 additions & 278 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/case-core-plugin-function/src/matchers/FunctionArgumentsMatcher.spec.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@ import {
55
import {
66
CaseConfigurationError,
77
CaseCoreError,
8+
DescribeSegment,
9+
describeMessage,
810
MatchContext,
11+
renderToString,
912
} from '@contract-case/case-plugin-base';
1013
import { FunctionArgumentMatcherExecutor } from './FunctionArgumentsMatcher';
1114

1215
describe('FunctionArgumentMatcherExecutor', () => {
1316
interface MockState {
1417
descendAndStripResult: any;
15-
descendAndDescribeResult: string;
18+
descendAndDescribeResult: DescribeSegment;
1619
descendAndCheckResult: any[];
1720
}
1821

@@ -54,23 +57,23 @@ describe('FunctionArgumentMatcherExecutor', () => {
5457
beforeEach(() => {
5558
mockMatchContext = createMockMatchContext({
5659
descendAndStripResult: [],
57-
descendAndDescribeResult: 'default description',
60+
descendAndDescribeResult: describeMessage('default description'),
5861
descendAndCheckResult: [],
5962
});
6063
});
6164

6265
describe('description function', () => {
6366
it('describes an invocation with no arguments', () => {
6467
expect(
65-
FunctionArgumentMatcherExecutor.describe(matcher, mockMatchContext),
68+
renderToString(FunctionArgumentMatcherExecutor.describe(matcher, mockMatchContext)),
6669
).toBe('An invocation of mockFunction()');
6770
});
6871

6972
describe('describes an invocation with arguments', () => {
7073
beforeEach(() => {
7174
mockMatchContext = createMockMatchContext({
7275
descendAndStripResult: [],
73-
descendAndDescribeResult: 'some description',
76+
descendAndDescribeResult: describeMessage('some description'),
7477
descendAndCheckResult: [],
7578
});
7679
});
@@ -82,10 +85,10 @@ describe('FunctionArgumentMatcherExecutor', () => {
8285
};
8386

8487
expect(
85-
FunctionArgumentMatcherExecutor.describe(
88+
renderToString(FunctionArgumentMatcherExecutor.describe(
8689
argsMatcher,
8790
mockMatchContext,
88-
),
91+
)),
8992
).toBe('An invocation of mockFunction( some description )');
9093
});
9194
});
@@ -121,7 +124,7 @@ describe('FunctionArgumentMatcherExecutor', () => {
121124
beforeEach(() => {
122125
mockMatchContext = createMockMatchContext({
123126
descendAndStripResult: [],
124-
descendAndDescribeResult: 'default description',
127+
descendAndDescribeResult: describeMessage('default description'),
125128
descendAndCheckResult: [],
126129
});
127130
});
@@ -147,7 +150,7 @@ describe('FunctionArgumentMatcherExecutor', () => {
147150
beforeEach(() => {
148151
mockMatchContext = createMockMatchContext({
149152
descendAndStripResult: 'stripped-expected',
150-
descendAndDescribeResult: 'default description',
153+
descendAndDescribeResult: describeMessage('default description'),
151154
descendAndCheckResult: [],
152155
});
153156
});
@@ -178,7 +181,7 @@ describe('FunctionArgumentMatcherExecutor', () => {
178181
beforeEach(() => {
179182
mockMatchContext = createMockMatchContext({
180183
descendAndStripResult: ['stripped'],
181-
descendAndDescribeResult: 'default description',
184+
descendAndDescribeResult: describeMessage('default description'),
182185
descendAndCheckResult: [],
183186
});
184187
});

packages/case-core-plugin-function/src/matchers/FunctionArgumentsMatcher.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ import {
1313
combineResultPromises,
1414
CaseCoreError,
1515
hasErrors,
16+
DescribeSegment,
17+
concatenateDescribe,
18+
describeJoin,
19+
describeMessage,
1620
} from '@contract-case/case-plugin-base';
1721
import { AnyData } from '@contract-case/case-plugin-dsl-types';
1822
import { getFunctionName } from './getFunctionName';
@@ -44,14 +48,19 @@ const strip = (
4448
const describe = (
4549
{ arguments: expectedArguments }: CoreFunctionArgumentsMatcher,
4650
context: MatchContext,
47-
): string =>
51+
): DescribeSegment =>
4852
expectedArguments.length === 0
49-
? `An invocation of ${getFunctionName(context)}()`
50-
: `An invocation of ${getFunctionName(context)}( ${expectedArguments
51-
.map((arg, index) =>
52-
context.descendAndDescribe(arg, addLocation(`[${index}]`, context)),
53-
)
54-
.join(', ')} )`;
53+
? describeMessage(`An invocation of ${getFunctionName(context)}()`)
54+
: concatenateDescribe(
55+
describeMessage(`An invocation of ${getFunctionName(context)}( `),
56+
describeJoin(
57+
', ',
58+
expectedArguments.map((arg, index) =>
59+
context.descendAndDescribe(arg, addLocation(`[${index}]`, context)),
60+
),
61+
),
62+
describeMessage(' )'),
63+
);
5564

5665
const check = async (
5766
matcher: CoreFunctionArgumentsMatcher,

packages/case-core-plugin-function/src/matchers/FunctionResultMatcher.spec.ts

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ import {
77
CaseConfigurationError,
88
CaseCoreError,
99
DataContext,
10+
DescribeSegment,
11+
describeMessage,
1012
Logger,
1113
MatchContext,
14+
renderToString,
1215
} from '@contract-case/case-plugin-base';
1316
import { AnyCaseMatcherOrData } from '@contract-case/case-plugin-dsl-types';
1417
import {
@@ -72,7 +75,7 @@ const MOCK_LOOKUP = {
7275
interface MockState {
7376
descendAndCheckResult: any[];
7477
descendAndStripResult: any;
75-
descendAndDescribeResult: string;
78+
descendAndDescribeResult: DescribeSegment;
7679
}
7780

7881
const createMockMatchContext = (state: MockState): MatchContext => ({
@@ -103,7 +106,7 @@ describe('FunctionResultMatcherExecutor', () => {
103106
mockMatchContext = createMockMatchContext({
104107
descendAndCheckResult: [],
105108
descendAndStripResult: 'stripped',
106-
descendAndDescribeResult: '"default description"',
109+
descendAndDescribeResult: describeMessage('"default description"'),
107110
});
108111
});
109112

@@ -122,24 +125,24 @@ describe('FunctionResultMatcherExecutor', () => {
122125
mockMatchContext = createMockMatchContext({
123126
descendAndCheckResult: [],
124127
descendAndStripResult: 'stripped',
125-
descendAndDescribeResult: 'some description',
128+
descendAndDescribeResult: describeMessage('some description'),
126129
});
127130
expect(
128-
FunctionResultMatcherExecutor.describe(
131+
renderToString(FunctionResultMatcherExecutor.describe(
129132
successMatcher,
130133
mockMatchContext,
131-
),
134+
)),
132135
).toBe('returns some description');
133136
});
134137

135138
it('describes error result', () => {
136139
mockMatchContext = createMockMatchContext({
137140
descendAndCheckResult: [],
138141
descendAndStripResult: 'stripped',
139-
descendAndDescribeResult: '"SomeError"',
142+
descendAndDescribeResult: describeMessage('"SomeError"'),
140143
});
141144
expect(
142-
FunctionResultMatcherExecutor.describe(errorMatcher, mockMatchContext),
145+
renderToString(FunctionResultMatcherExecutor.describe(errorMatcher, mockMatchContext)),
143146
).toBe('throwing a SomeError');
144147
});
145148

@@ -154,13 +157,13 @@ describe('FunctionResultMatcherExecutor', () => {
154157
mockMatchContext = createMockMatchContext({
155158
descendAndCheckResult: [],
156159
descendAndStripResult: 'stripped',
157-
descendAndDescribeResult: '"SomeError"',
160+
descendAndDescribeResult: describeMessage('"SomeError"'),
158161
});
159162

160-
const result = FunctionResultMatcherExecutor.describe(
163+
const result = renderToString(FunctionResultMatcherExecutor.describe(
161164
errorMatcherWithMessage,
162165
mockMatchContext,
163-
);
166+
));
164167

165168
// The result should contain both the error class and message
166169
expect(result).toContain('throwing a SomeError');
@@ -175,7 +178,7 @@ describe('FunctionResultMatcherExecutor', () => {
175178
mockMatchContext = createMockMatchContext({
176179
descendAndCheckResult: [],
177180
descendAndStripResult: 'stripped',
178-
descendAndDescribeResult: '"default"',
181+
descendAndDescribeResult: describeMessage('"default"'),
179182
});
180183
});
181184

@@ -235,7 +238,7 @@ describe('FunctionResultMatcherExecutor', () => {
235238
mockMatchContext = createMockMatchContext({
236239
descendAndCheckResult: [],
237240
descendAndStripResult: 'stripped-expected',
238-
descendAndDescribeResult: '"default"',
241+
descendAndDescribeResult: describeMessage('"default"'),
239242
});
240243
});
241244

@@ -275,7 +278,7 @@ describe('FunctionResultMatcherExecutor', () => {
275278
mockMatchContext = createMockMatchContext({
276279
descendAndCheckResult: [],
277280
descendAndStripResult: 'stripped',
278-
descendAndDescribeResult: '"default"',
281+
descendAndDescribeResult: describeMessage('"default"'),
279282
});
280283
});
281284

@@ -297,7 +300,7 @@ describe('FunctionResultMatcherExecutor', () => {
297300
mockMatchContext = createMockMatchContext({
298301
descendAndCheckResult: [],
299302
descendAndStripResult: 'stripped-expected',
300-
descendAndDescribeResult: '"default"',
303+
descendAndDescribeResult: describeMessage('"default"'),
301304
});
302305
});
303306

@@ -324,7 +327,7 @@ describe('FunctionResultMatcherExecutor', () => {
324327
mockMatchContext = createMockMatchContext({
325328
descendAndCheckResult: [],
326329
descendAndStripResult: 'stripped',
327-
descendAndDescribeResult: '"default"',
330+
descendAndDescribeResult: describeMessage('"default"'),
328331
});
329332
});
330333

packages/case-core-plugin-function/src/matchers/FunctionResultMatcher.ts

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ import {
1111
addLocation,
1212
matchingError,
1313
CaseConfigurationError,
14+
DescribeSegment,
15+
concatenateDescribe,
16+
describeMessage,
17+
renderToString,
1418
} from '@contract-case/case-plugin-base';
1519
import { AnyData } from '@contract-case/case-plugin-dsl-types';
1620
import { isObject } from '../entities';
@@ -68,25 +72,42 @@ const strip = (
6872
const describe = (
6973
matcher: CoreFunctionSuccessResultMatcher | CoreFunctionErrorResultMatcher,
7074
context: MatchContext,
71-
): string =>
72-
isSuccessResult(matcher)
73-
? `returns ${context.descendAndDescribe(
75+
): DescribeSegment => {
76+
if (isSuccessResult(matcher)) {
77+
return concatenateDescribe(
78+
describeMessage('returns '),
79+
context.descendAndDescribe(
7480
matcher.success,
7581
addLocation(`returnValue`, context),
76-
)}`
77-
: `throwing a ${JSON.parse(
78-
context.descendAndDescribe(
79-
matcher.errorClassName,
80-
addLocation(`errorClassName`, context),
82+
),
83+
);
84+
}
85+
86+
const segments: DescribeSegment[] = [
87+
describeMessage(
88+
`throwing a ${JSON.parse(
89+
renderToString(
90+
context.descendAndDescribe(
91+
matcher.errorClassName,
92+
addLocation(`errorClassName`, context),
93+
),
8194
),
82-
)}${
83-
'message' in matcher
84-
? ` with message: ${context.descendAndDescribe(
85-
matcher.message,
86-
addLocation(`message`, context),
87-
)}`
88-
: ''
89-
}`;
95+
)}`,
96+
),
97+
];
98+
99+
if ('message' in matcher) {
100+
segments.push(
101+
describeMessage(' with message: '),
102+
context.descendAndDescribe(
103+
matcher.message,
104+
addLocation(`message`, context),
105+
),
106+
);
107+
}
108+
109+
return concatenateDescribe(...segments);
110+
};
90111

91112
const parseActualSuccess = (
92113
actual: unknown,

packages/case-core-plugin-function/src/matchers/getFunctionName.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
CaseConfigurationError,
33
DataContext,
4+
describeMessage,
45
Logger,
56
MatchContext,
67
} from '@contract-case/case-plugin-base';
@@ -63,7 +64,7 @@ const EMPTY_MATCH_CONTEXT: MatchContext = {
6364
...EMPTY_DATA_CONTEXT,
6465
descendAndCheck: () => Promise.resolve([]),
6566
descendAndStrip: () => [],
66-
descendAndDescribe: () => 'during testing',
67+
descendAndDescribe: () => describeMessage('during testing'),
6768
selfVerify: () => Promise.resolve(),
6869
...MOCK_LOOKUP,
6970
makeLookup: () => MOCK_LOOKUP,

packages/case-core-plugin-http/src/matchers/HttpBasicAuthMatcher.spec.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ import {
55
import {
66
CaseConfigurationError,
77
DataContext,
8+
DescribeSegment,
9+
describeMessage,
810
Logger,
911
MatchContext,
12+
renderToString,
1013
} from '@contract-case/case-plugin-base';
1114
import { HttpBasicAuthMatcher } from './HttpBasicAuthMatcher';
1215

@@ -66,7 +69,7 @@ const MOCK_LOOKUP = {
6669
interface MockState {
6770
descendAndCheckResult: any[];
6871
descendAndStripResult: any;
69-
descendAndDescribeResult: string;
72+
descendAndDescribeResult: DescribeSegment;
7073
}
7174

7275
const createMockMatchContext = (state: MockState): MatchContext => ({
@@ -94,7 +97,7 @@ describe('HttpBasicAuthMatcher', () => {
9497
mockMatchContext = createMockMatchContext({
9598
descendAndCheckResult: [],
9699
descendAndStripResult: 'stripped',
97-
descendAndDescribeResult: '"default description"',
100+
descendAndDescribeResult: describeMessage('"default description"'),
98101
});
99102
});
100103

@@ -103,9 +106,9 @@ describe('HttpBasicAuthMatcher', () => {
103106
mockMatchContext = createMockMatchContext({
104107
descendAndCheckResult: [],
105108
descendAndStripResult: 'stripped',
106-
descendAndDescribeResult: 'description',
109+
descendAndDescribeResult: describeMessage('description'),
107110
});
108-
expect(HttpBasicAuthMatcher.describe(matcher, mockMatchContext)).toBe(
111+
expect(renderToString(HttpBasicAuthMatcher.describe(matcher, mockMatchContext))).toBe(
109112
"http basic auth with username='description' and password=description",
110113
);
111114
});
@@ -156,7 +159,7 @@ describe('HttpBasicAuthMatcher', () => {
156159
const context = createMockMatchContext({
157160
descendAndCheckResult: [],
158161
descendAndStripResult: 'stripped',
159-
descendAndDescribeResult: 'description',
162+
descendAndDescribeResult: describeMessage('description'),
160163
});
161164

162165
const expected = Buffer.from('stripped:stripped').toString('base64');
@@ -169,7 +172,7 @@ describe('HttpBasicAuthMatcher', () => {
169172
const context = createMockMatchContext({
170173
descendAndCheckResult: [],
171174
descendAndStripResult: 123,
172-
descendAndDescribeResult: 'description',
175+
descendAndDescribeResult: describeMessage('description'),
173176
});
174177

175178
expect(() => HttpBasicAuthMatcher.strip(matcher, context)).toThrow(

0 commit comments

Comments
 (0)