Skip to content

Commit b896d8c

Browse files
committed
refactor
1 parent 5144aa9 commit b896d8c

5 files changed

Lines changed: 142 additions & 148 deletions

File tree

src/codegen/codegen.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ describe('Code generation', () => {
423423
params = { headers: {}, cookies: {} }
424424
url = http.url\`http://test.k6.io/api/v1/foo\`
425425
resp = http.request('POST', url, null, params)
426-
check(resp, { 'status equals 200': (r) => r.status === 200, })
426+
check(resp, { 'status equals recorded value': (r) => r.status === 200, })
427427
`
428428

429429
expect(

src/rules/rules.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ export function applyRules(recording: ProxyData[], rules: TestRule[]) {
3434
after: [],
3535
})
3636
)
37-
console.log('rules applied', requestSnippetSchemas)
3837

3938
return { requestSnippetSchemas, ruleInstances }
4039
}

src/rules/verification.test.ts

Lines changed: 4 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ describe('createVerificationRuleInstance', () => {
5151

5252
expect(result.after).toHaveLength(1)
5353
expect(result.after[0]).toContain(
54-
"'status equals 200': (r) => r.status === 200"
54+
"'status equals recorded value': (r) => r.status === 200"
5555
)
5656
})
5757

@@ -74,43 +74,6 @@ describe('createVerificationRuleInstance', () => {
7474

7575
expect(result.after).toHaveLength(0)
7676
})
77-
78-
it('applies multiple verification rules to the same request', () => {
79-
const rule1 = createMockVerificationRule({
80-
filter: { path: '/api/v1/users' },
81-
})
82-
const rule2 = createMockVerificationRule({
83-
filter: { path: '/api/v1/users' },
84-
})
85-
86-
const instance1 = createInstance(rule1)
87-
const instance2 = createInstance(rule2)
88-
89-
const mockRequestSnippet = createMockRequestSnippet({
90-
response: { statusCode: 200 },
91-
request: {
92-
path: '/api/v1/users',
93-
url: 'http://example.com/api/v1/users',
94-
},
95-
})
96-
97-
const result1 = instance1.apply(mockRequestSnippet)
98-
const result2 = instance2.apply({
99-
...result1,
100-
data: {
101-
...result1.data,
102-
response: createResponse({ statusCode: 201 }),
103-
},
104-
})
105-
106-
expect(result2.after).toHaveLength(2)
107-
expect(result2.after[0]).toContain(
108-
"'status equals 200': (r) => r.status === 200"
109-
)
110-
expect(result2.after[1]).toContain(
111-
"'status equals 201': (r) => r.status === 201"
112-
)
113-
})
11477
})
11578

11679
describe('operators', () => {
@@ -129,7 +92,7 @@ describe('createVerificationRuleInstance', () => {
12992

13093
expect(result.after).toHaveLength(1)
13194
expect(result.after[0]).toContain(
132-
"'status equals 200': (r) => r.status === 200"
95+
"'status equals recorded value': (r) => r.status === 200"
13396
)
13497
})
13598

@@ -192,7 +155,7 @@ describe('createVerificationRuleInstance', () => {
192155

193156
expect(result.after).toHaveLength(1)
194157
expect(result.after[0]).toContain(
195-
"'status equals 200': (r) => r.status === 200"
158+
"'status equals recorded value': (r) => r.status === 200"
196159
)
197160
})
198161

@@ -274,7 +237,7 @@ describe('createVerificationRuleInstance', () => {
274237

275238
expect(result.after).toHaveLength(1)
276239
expect(result.after[0]).toContain(
277-
"'status equals 200': (r) => r.status === 200"
240+
"'status equals recorded value': (r) => r.status === 200"
278241
)
279242
})
280243

src/rules/verification.ts

Lines changed: 6 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,11 @@
11
import { RequestSnippetSchema } from '@/types'
22
import { VerificationRule, VerificationRuleInstance } from '@/types/rules'
33
import { matchFilter } from './utils'
4-
import { exhaustive } from '@/utils/typescript'
5-
6-
type CheckValue = string | number
7-
8-
// TODO: this is redundant
9-
function getValueFromRule(
10-
rule: VerificationRule,
11-
response: RequestSnippetSchema['data']['response']
12-
): CheckValue {
13-
if (!response) return ''
14-
const { type } = rule.value
15-
16-
switch (type) {
17-
case 'recordedValue':
18-
return rule.target === 'status' ? response.statusCode : response.content
19-
case 'string':
20-
return rule.value.value
21-
case 'variable':
22-
return `VARS['${rule.value.variableName}']`
23-
default:
24-
return exhaustive(type)
25-
}
26-
}
27-
28-
const getExpectedValue = (
29-
rule: VerificationRule,
30-
value: CheckValue
31-
): CheckValue => {
32-
switch (rule.value.type) {
33-
case 'recordedValue':
34-
return rule.target === 'status'
35-
? value
36-
: `String.raw\`${escapeBackticksAndDollarSign(value.replace(/(?:\r\n|\r|\n)/g, ''))}\``
37-
case 'string':
38-
return rule.target === 'status' ? value : `'${value}'`
39-
case 'variable':
40-
return rule.target === 'status' ? `Number(${value})` : value
41-
default:
42-
return exhaustive(rule.value)
43-
}
44-
}
45-
46-
function getTarget(rule: VerificationRule) {
47-
const property = rule.target === 'status' ? 'r.status' : 'r.body'
48-
49-
if (rule.value.type === 'recordedValue' && rule.target === 'body') {
50-
return `${property}.replace(/(?:\\r\\n|\\r|\\n)/g, '')`
51-
}
52-
53-
return property
54-
}
55-
56-
function getCheckExpression(rule: VerificationRule, value: CheckValue): string {
57-
const target = getTarget(rule)
58-
const expectedValue = getExpectedValue(rule, value)
59-
console.log('expectedValue', expectedValue)
60-
61-
switch (rule.operator) {
62-
case 'equals':
63-
return `${target} === ${expectedValue}`
64-
case 'contains':
65-
return `${target}.includes(${expectedValue})`
66-
case 'notContains':
67-
return `!${target}.includes(${expectedValue})`
68-
default:
69-
return exhaustive(rule.operator)
70-
}
71-
}
72-
73-
function getValueDescription(rule: VerificationRule, value: CheckValue) {
74-
switch (rule.value.type) {
75-
case 'recordedValue':
76-
return rule.target === 'body' ? 'recorded value' : value
77-
case 'string':
78-
return value
79-
case 'variable':
80-
return `variable "${rule.value.variableName}"`
81-
default:
82-
return exhaustive(rule.value)
83-
}
84-
}
85-
86-
function getCheckDescription(
87-
rule: VerificationRule,
88-
value: CheckValue
89-
): string {
90-
const valueDescription = getValueDescription(rule, value)
91-
92-
switch (rule.operator) {
93-
case 'equals':
94-
return `${rule.target} equals ${valueDescription}`
95-
case 'contains':
96-
return `${rule.target} contains ${valueDescription}`
97-
case 'notContains':
98-
return `${rule.target} does not contain ${valueDescription}`
99-
default:
100-
return exhaustive(rule.operator)
101-
}
102-
}
4+
import {
5+
getCheckDescription,
6+
getCheckExpression,
7+
getValueFromRule,
8+
} from './verification.utils'
1039

10410
export function createVerificationRuleInstance(
10511
rule: VerificationRule
@@ -129,8 +35,8 @@ export function createVerificationRuleInstance(
12935
state.matchedRequestIds = [...state.matchedRequestIds, id]
13036

13137
const value = getValueFromRule(rule, response)
38+
const checkDescription = getCheckDescription(rule)
13239
const checkExpression = getCheckExpression(rule, value)
133-
const checkDescription = getCheckDescription(rule, value)
13440

13541
const verificationSnippet = `check(resp, { '${checkDescription}': (r) => ${checkExpression}, })`
13642

@@ -141,8 +47,3 @@ export function createVerificationRuleInstance(
14147
},
14248
}
14349
}
144-
145-
// Without escaping, backticks and dollar sign break the String.raw template literal
146-
function escapeBackticksAndDollarSign(str: string) {
147-
return str.replace(/\$/g, '${"$"}').replace(/`/g, '${"`"}')
148-
}

src/rules/verification.utils.ts

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import { Response } from '@/types'
2+
import { VerificationRule } from '@/types/rules'
3+
import { exhaustive } from '@/utils/typescript'
4+
5+
const NEWLINE_REGEX = /(?:\r\n|\r|\n)/g
6+
7+
export function getValueFromRule(rule: VerificationRule, response: Response) {
8+
const { type } = rule.value
9+
10+
switch (type) {
11+
case 'recordedValue':
12+
return getRecordedValue(rule.target, response)
13+
case 'string':
14+
return getStringValue(rule.target, rule.value.value)
15+
case 'variable':
16+
return getVariableValue(rule.target, rule.value.variableName)
17+
default:
18+
return exhaustive(type)
19+
}
20+
}
21+
22+
export function getCheckExpression(
23+
rule: VerificationRule,
24+
value: string | number
25+
): string {
26+
const target = getTarget(rule)
27+
28+
switch (rule.operator) {
29+
case 'equals':
30+
return `${target} === ${value}`
31+
case 'contains':
32+
return `${target}.includes(${value})`
33+
case 'notContains':
34+
return `!${target}.includes(${value})`
35+
default:
36+
return exhaustive(rule.operator)
37+
}
38+
}
39+
40+
export function getCheckDescription(rule: VerificationRule): string {
41+
const valueDescription = getValueDescription(rule)
42+
43+
switch (rule.operator) {
44+
case 'equals':
45+
return `${rule.target} equals ${valueDescription}`
46+
case 'contains':
47+
return `${rule.target} contains ${valueDescription}`
48+
case 'notContains':
49+
return `${rule.target} does not contain ${valueDescription}`
50+
default:
51+
return exhaustive(rule.operator)
52+
}
53+
}
54+
55+
function getRecordedValue(
56+
target: VerificationRule['target'],
57+
response: Response
58+
) {
59+
switch (target) {
60+
case 'status':
61+
return response.statusCode
62+
case 'body': {
63+
// Remove newlines when comparing the body to a recorded value
64+
const singleLineContent = response.content.replace(NEWLINE_REGEX, '')
65+
const escapedContent = escapeBackticksAndDollarSign(singleLineContent)
66+
67+
return `String.raw\`${escapedContent}\``
68+
}
69+
default:
70+
return exhaustive(target)
71+
}
72+
}
73+
74+
function getStringValue(target: VerificationRule['target'], value: string) {
75+
switch (target) {
76+
case 'status':
77+
return value
78+
case 'body':
79+
return `'${value}'`
80+
default:
81+
return exhaustive(target)
82+
}
83+
}
84+
85+
function getVariableValue(
86+
target: VerificationRule['target'],
87+
variableName: string
88+
) {
89+
switch (target) {
90+
case 'status':
91+
return `Number(VARS['${variableName}'])`
92+
case 'body':
93+
return `VARS['${variableName}']`
94+
default:
95+
return exhaustive(target)
96+
}
97+
}
98+
99+
function getTarget(rule: VerificationRule) {
100+
switch (rule.target) {
101+
case 'status':
102+
return 'r.status'
103+
case 'body': {
104+
// Remove newlines when comparing the body to a recorded value
105+
if (rule.value.type === 'recordedValue' && rule.target === 'body') {
106+
return `r.body.replace(${NEWLINE_REGEX}, '')`
107+
}
108+
return 'r.body'
109+
}
110+
default:
111+
return exhaustive(rule.target)
112+
}
113+
}
114+
115+
function getValueDescription(rule: VerificationRule) {
116+
switch (rule.value.type) {
117+
case 'recordedValue':
118+
return 'recorded value'
119+
case 'string':
120+
return rule.value.value
121+
case 'variable':
122+
return `variable "${rule.value.variableName}"`
123+
default:
124+
return exhaustive(rule.value)
125+
}
126+
}
127+
128+
// Without escaping, backticks and dollar sign break the String.raw template literal
129+
function escapeBackticksAndDollarSign(str: string) {
130+
return str.replace(/\$/g, '${"$"}').replace(/`/g, '${"`"}')
131+
}

0 commit comments

Comments
 (0)