Skip to content

Commit 25a5b97

Browse files
authored
[patch] fix pseudo regexp cases (#24)
1 parent 7dbe51e commit 25a5b97

File tree

3 files changed

+112
-35
lines changed

3 files changed

+112
-35
lines changed

README.pack.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -280,10 +280,8 @@ Here are some examples of pseudo regexp:
280280
- `GREP='@smoke&!@P2&!@P1'` - runs all tests with `smoke` and without `@P2` and without `@P1`
281281
- `GREP='(@P1|@P2)&!@smoke'` or `GREP='(@P[12])&!@smoke'` - runs all tests with `@P2` or `@P1` and without `@smoke`
282282

283-
**Minor known issue with pseudo regexp**:
284-
285-
- line `@suite @test` will NOT match this expression: `GREP='(@test&@suite)|@tag'`(for `@test @suite` matches), as a workaround rewrite to `GREP='(@test|@tag)&(@suite|@tag)'`
286-
- all other cases pass - you can check tested cases here if you are interested [tests/test-folder/regexp.test.ts](https://github.com/mmisty/cypress-grep/blob/main/tests/test-folder/regexp.test.ts#L5)
283+
#### dev
284+
- you can check tested cases here if you are interested [tests/test-folder/regexp.test.ts](https://github.com/mmisty/cypress-grep/blob/main/tests/test-folder/regexp.test.ts#L5)
287285

288286
### Select tests by regexp
289287

src/utils/regexp.ts

+65-19
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,83 @@
1-
// when experession !(<expression>)
2-
const transformReversed = (isInversed: boolean, s: string) => {
3-
s = isInversed ? s.slice(2) : s;
4-
s = isInversed ? s.slice(0, s.length - 2) : s;
1+
type Replacement = { mapName: string; exp: string; inverse: boolean };
52

6-
return s;
7-
};
3+
/**
4+
* replace all parenthesis groups with placeholder
5+
* @param input
6+
* @param replacements
7+
* @param num
8+
*/
9+
const replaceParenthesisGroups = (input: string, replacements: Replacement[], num = 1): string => {
10+
let replaced = input;
11+
const groupsNeg = input.match(/!\(([^()]*)\)/);
12+
const groups = input.match(/\(([^()]*)\)/);
813

9-
export const selectionTestGrep = (str: string): RegExp => {
10-
if (str.startsWith('=')) {
11-
// expressions like '=/hello$/i'
12-
const beg = str.slice(1);
13-
const endOfExpr = beg.lastIndexOf('/');
14-
const flags = endOfExpr < beg.length - 1 ? beg.slice(endOfExpr + 1) : '';
15-
const expr = beg.slice(beg.indexOf('/') + 1, endOfExpr);
14+
if (!groupsNeg && !groups) {
15+
return replaced;
16+
}
1617

17-
return new RegExp(expr, flags);
18+
const replaceExpression = (expression: string, group: string, inverse: boolean) => {
19+
const mapName = `##R${num}##`;
20+
replacements.push({ mapName, exp: group, inverse });
21+
replaced = replaced.replace(expression, mapName);
22+
23+
return replaceParenthesisGroups(replaced, replacements, num + 1);
24+
};
25+
26+
if (groupsNeg) {
27+
return replaceExpression(groupsNeg[0], groupsNeg[1], true);
28+
} else if (groups) {
29+
return replaceExpression(groups[0], groups[1], false);
1830
}
1931

20-
const isInverse = str.startsWith('!(');
21-
const transformed = transformReversed(isInverse, str);
32+
return replaced;
33+
};
2234

23-
const reg = transformed
35+
/**
36+
* no parenthesis in the group
37+
* @param exp
38+
* @param inverse
39+
*/
40+
const convertOneGroup = (exp: string, inverse: boolean): string => {
41+
const reg = exp
2442
.split('/')
2543
.map(t => (t.startsWith('!') ? t.replace(/^!(.*)/, '^(?!.*$1.*)') : t))
2644
.map(t =>
2745
t.indexOf('&') !== -1
2846
? `${t
2947
.split('&')
30-
.map(nd => (nd.startsWith('!') ? nd.replace(/^!(.*)/, '^(?!.*$1)') : nd.replace(/^(.*)/, '(?=.*$1)')))
48+
.map(nd => (nd.startsWith('!') ? nd.replace(/^!(.*)/, '^(?!.*$1.*)') : nd.replace(/^(.*)/, '(?=.*$1)')))
3149
.join('+')}+`
3250
: t,
3351
)
3452
.join('|');
3553

36-
return new RegExp(isInverse ? `^(?!.*${reg}).*` : `${reg}.*`, 'i');
54+
const res = reg.indexOf('|') !== -1 ? `(${reg})` : reg;
55+
56+
return inverse ? `^(?!.*${res}.*)` : `${res}`;
57+
};
58+
59+
export const selectionTestGrep = (str: string): RegExp => {
60+
if (str.startsWith('=')) {
61+
// expressions like '=/hello$/i'
62+
const beg = str.slice(1);
63+
const endOfExpr = beg.lastIndexOf('/');
64+
const flags = endOfExpr < beg.length - 1 ? beg.slice(endOfExpr + 1) : '';
65+
const expr = beg.slice(beg.indexOf('/') + 1, endOfExpr);
66+
67+
return new RegExp(expr, flags);
68+
}
69+
70+
const replacements: Replacement[] = [];
71+
const replacedString = replaceParenthesisGroups(str, replacements);
72+
let convertedString = convertOneGroup(replacedString, false);
73+
const groups = replacements.map(t => ({ ...t, reg: convertOneGroup(t.exp, t.inverse) }));
74+
75+
// last group should be converted first
76+
groups
77+
.sort((a, b) => (a.mapName > b.mapName ? -1 : 1))
78+
.forEach(r => {
79+
convertedString = convertedString.replace(r.mapName, r.reg);
80+
});
81+
82+
return new RegExp(`${convertedString}.*`, 'i');
3783
};

tests/test-folder/regexp.test.ts

+45-12
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,39 @@ describe('suite', () => {
3232
{ expectMatch: false, testLine: 'no' },
3333
],
3434
},
35+
{
36+
desc: 'parenthesis',
37+
GREP: '(my test)',
38+
regExpected: /my test.*/i,
39+
cases: [
40+
{ expectMatch: true, testLine: 'hello my test' },
41+
{ expectMatch: false, testLine: 'my tes hello ' },
42+
],
43+
},
44+
{
45+
desc: 'parenthesis several',
46+
GREP: '!(my test)&!(his test)',
47+
regExpected: /(?=.*^(?!.*my test.*))+(?=.*^(?!.*his test.*))+.*/i,
48+
cases: [
49+
{ expectMatch: true, testLine: 'her test' },
50+
{ expectMatch: false, testLine: 'my test' },
51+
{ expectMatch: false, testLine: 'his test' },
52+
{ expectMatch: true, testLine: 'his tesPP' },
53+
],
54+
},
55+
{
56+
desc: 'parenthesis several complex',
57+
GREP: '(((her)&!(my test|his test)))',
58+
regExpected: /(?=.*her)+(?=.*^(?!.*(my test|his test).*))+.*/i,
59+
cases: [
60+
{ expectMatch: true, testLine: 'test her' },
61+
{ expectMatch: true, testLine: 'her test' },
62+
{ expectMatch: false, testLine: 'her his test' },
63+
{ expectMatch: false, testLine: 'her my test' },
64+
{ expectMatch: false, testLine: 'my test' },
65+
{ expectMatch: false, testLine: 'his test' },
66+
],
67+
},
3568
{
3669
desc: 'tag with dot encoded',
3770
GREP: '@test\\.1',
@@ -71,7 +104,7 @@ describe('suite', () => {
71104
{
72105
desc: 'or',
73106
GREP: '@e2e|@regression',
74-
regExpected: /@e2e|@regression.*/i,
107+
regExpected: /(@e2e|@regression).*/i,
75108
cases: [
76109
{ expectMatch: true, testLine: 'sdd @e2e dsd' },
77110
{ expectMatch: true, testLine: 'sd @regression' },
@@ -84,7 +117,7 @@ describe('suite', () => {
84117
{
85118
desc: 'or',
86119
GREP: '@e2e/@regression',
87-
regExpected: /@e2e|@regression.*/i,
120+
regExpected: /(@e2e|@regression).*/i,
88121
cases: [
89122
{ expectMatch: true, testLine: 'sdd @e2e dsd' },
90123
{ expectMatch: true, testLine: 'sd @regression' },
@@ -127,7 +160,7 @@ describe('suite', () => {
127160
{
128161
desc: 'tag and not',
129162
GREP: '@test&!suite',
130-
regExpected: /(?=.*@test)+^(?!.*suite)+.*/i,
163+
regExpected: /(?=.*@test)+^(?!.*suite.*)+.*/i,
131164
cases: [
132165
{ expectMatch: true, testLine: 'abc @test my world' },
133166
{ expectMatch: true, testLine: '@test' },
@@ -140,7 +173,7 @@ describe('suite', () => {
140173
{
141174
desc: 'not and not',
142175
GREP: '!@test&!@suite',
143-
regExpected: /(?=.*^(?!.*@test)+^(?!.*@suite.*))+.*/i,
176+
regExpected: /(?=.*^(?!.*@test)+^(?!.*@suite.*).*)+.*/i,
144177
cases: [
145178
{ expectMatch: true, testLine: 'abc my world' },
146179
{ expectMatch: false, testLine: '@test' },
@@ -154,9 +187,10 @@ describe('suite', () => {
154187
{
155188
desc: 'not and not Inversed',
156189
GREP: '!(!@test&!@suite)',
157-
regExpected: /^(?!.*(?=.*^(?!.*@test)+^(?!.*@suit.*))+).*/i,
190+
regExpected: /^(?!.*(?=.*^(?!.*@test)+^(?!.*@suite.*).*)+.*).*/i,
158191
cases: [
159192
{ expectMatch: false, testLine: 'abc my world' },
193+
{ expectMatch: false, testLine: '@suit abc my' },
160194
{ expectMatch: true, testLine: '@test' },
161195
{ expectMatch: true, testLine: '@TEST' },
162196
{ expectMatch: true, testLine: 'abc @test my suite' },
@@ -182,7 +216,7 @@ describe('suite', () => {
182216
{
183217
desc: 'not and or combination different order',
184218
GREP: '(@suite|@tag)&!@test',
185-
regExpected: /(?=.*(@suite|@tag))+^(?!.*@test)+.*/i,
219+
regExpected: /(?=.*(@suite|@tag))+^(?!.*@test.*)+.*/i,
186220
cases: [
187221
{ expectMatch: false, testLine: 'abc my @test world' },
188222
{ expectMatch: false, testLine: 'abc @suite @tag my @test world' },
@@ -197,16 +231,15 @@ describe('suite', () => {
197231
{
198232
desc: 'and with parenthesis and or combination',
199233
GREP: '(@test&@suite)|@tag',
200-
regExpected: /(?=.*(@test)+(?=.*@suite)|@tag)+.*/i,
234+
regExpected: /((?=.*@test)+(?=.*@suite)+|@tag).*/i,
201235
cases: [
202236
{ expectMatch: true, testLine: 'abc my @test @world @suite' },
203237
{ expectMatch: false, testLine: 'abc my @suite' },
204238
{ expectMatch: false, testLine: 'abc my @test' },
205239
{ expectMatch: true, testLine: 'abc my @tag' },
206240
{ expectMatch: true, testLine: 'abc my @test @tag' },
207241
{ expectMatch: true, testLine: 'abc@suite my @test @tag' },
208-
// this case does not work
209-
{ expectMatch: true, testLine: '@suite @test', fixThis: true, actualResult: false },
242+
{ expectMatch: true, testLine: '@suite @test' },
210243
],
211244
},
212245
{
@@ -226,10 +259,11 @@ describe('suite', () => {
226259
{
227260
desc: 'not with parenthesis',
228261
GREP: '!(@test&@suite)',
229-
regExpected: /^(?!.*(?=.*@test)+(?=.*@suit)+).*/i,
262+
regExpected: /^(?!.*(?=.*@test)+(?=.*@suite)+.*).*/i,
230263
cases: [
231264
{ expectMatch: false, testLine: '@test @suite' },
232265
{ expectMatch: false, testLine: '@suite @test' },
266+
{ expectMatch: true, testLine: '@suit @test' },
233267
{ expectMatch: true, testLine: 'no suite test' },
234268
{ expectMatch: true, testLine: 'only @test' },
235269
{ expectMatch: true, testLine: 'only @TEST' },
@@ -239,7 +273,6 @@ describe('suite', () => {
239273
])
240274
.each(t => [{ desc: `: '${t.GREP}'` }])
241275
.each(t => t.cases)
242-
243276
// .only(t => t.id === '1')
244277
.run(t => {
245278
const regActual = selectionTestGrep(t.GREP);
@@ -251,7 +284,7 @@ describe('suite', () => {
251284
}
252285

253286
// remove actualResult when fixed
254-
if (t.actualResult ?? t.expectMatch) {
287+
if (t.expectMatch) {
255288
expect(t.testLine).toMatch(regActual);
256289
} else {
257290
expect(t.testLine).not.toMatch(regActual);

0 commit comments

Comments
 (0)