@rstest/browser 0.10.5 → 0.10.6
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/dist/hostController.d.ts +1 -0
- package/dist/index.js +71 -14
- package/package.json +6 -6
- package/src/hostController.ts +175 -26
package/dist/hostController.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export declare const createBrowserRsbuildDevConfig: (_isWatchMode: boolean) => {
|
|
|
25
25
|
logLevel: 'error';
|
|
26
26
|
};
|
|
27
27
|
};
|
|
28
|
+
export declare const createBrowserContextExcludeRegExp: (patterns: string[], projectRoot: string) => RegExp | null;
|
|
28
29
|
// ============================================================================
|
|
29
30
|
// Main Entry Point
|
|
30
31
|
// ============================================================================
|
package/dist/index.js
CHANGED
|
@@ -3002,7 +3002,8 @@ const globToRegexp = (glob)=>{
|
|
|
3002
3002
|
const regex = picomatch_default().makeRe(glob, {
|
|
3003
3003
|
fastpaths: false,
|
|
3004
3004
|
noglobstar: false,
|
|
3005
|
-
bash: false
|
|
3005
|
+
bash: false,
|
|
3006
|
+
dot: true
|
|
3006
3007
|
});
|
|
3007
3008
|
if (!regex) throw new Error(`Invalid glob pattern: ${glob}`);
|
|
3008
3009
|
if (!glob.startsWith('./')) return regex;
|
|
@@ -3022,20 +3023,76 @@ const globPatternsToRegExp = (patterns)=>{
|
|
|
3022
3023
|
});
|
|
3023
3024
|
return new RegExp(`(?:${regexParts.join('|')})$`);
|
|
3024
3025
|
};
|
|
3025
|
-
const
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3026
|
+
const REGEXP_SPECIAL_CHARACTERS = /[|\\{}()[\]^$+*?.]/g;
|
|
3027
|
+
const PATH_SEPARATOR_SOURCE = String.raw`[\\/]`;
|
|
3028
|
+
const WINDOWS_ABSOLUTE_PATH_SOURCE = String.raw`[A-Za-z]:[\\/]`;
|
|
3029
|
+
const escapeRegExp = (value)=>value.replace(REGEXP_SPECIAL_CHARACTERS, '\\$&');
|
|
3030
|
+
const normalizePathForRegExp = (value)=>normalize(value).replaceAll('\\', '/');
|
|
3031
|
+
const normalizeExcludePatternForRegExp = (value)=>value.startsWith('./') ? `./${normalizePathForRegExp(value.substring(2))}` : normalizePathForRegExp(value);
|
|
3032
|
+
const isAbsolutePatternForRegExp = (value)=>value.startsWith('/') || /^[A-Za-z]:\//.test(value);
|
|
3033
|
+
const isEscapedRegExpCharacter = (source, index)=>{
|
|
3034
|
+
let backslashCount = 0;
|
|
3035
|
+
for(let current = index - 1; current >= 0 && '\\' === source[current]; current--)backslashCount++;
|
|
3036
|
+
return backslashCount % 2 === 1;
|
|
3037
|
+
};
|
|
3038
|
+
const replacePathSeparatorsInRegExpSource = (source)=>{
|
|
3039
|
+
let result = '';
|
|
3040
|
+
let inCharacterClass = false;
|
|
3041
|
+
for(let index = 0; index < source.length; index++){
|
|
3042
|
+
const character = source[index];
|
|
3043
|
+
const isEscaped = isEscapedRegExpCharacter(source, index);
|
|
3044
|
+
if ('[' === character && !isEscaped) inCharacterClass = true;
|
|
3045
|
+
if (!inCharacterClass && '\\' === character && '/' === source[index + 1]) {
|
|
3046
|
+
result += PATH_SEPARATOR_SOURCE;
|
|
3047
|
+
index++;
|
|
3048
|
+
continue;
|
|
3035
3049
|
}
|
|
3050
|
+
result += character;
|
|
3051
|
+
if (']' === character && !isEscaped) inCharacterClass = false;
|
|
3052
|
+
}
|
|
3053
|
+
return result;
|
|
3054
|
+
};
|
|
3055
|
+
const createRelativeContextExcludeSource = (source, normalizedPattern)=>{
|
|
3056
|
+
if (normalizedPattern.startsWith('./')) return source;
|
|
3057
|
+
return normalizedPattern.startsWith('**/') ? `(?:(?:${source})|\\.(?:${source}))` : `(?:(?:${source})|\\.${PATH_SEPARATOR_SOURCE}(?:${source}))`;
|
|
3058
|
+
};
|
|
3059
|
+
const createProjectAbsoluteExcludeSource = (source, normalizedPattern)=>normalizedPattern.startsWith('./') || normalizedPattern.startsWith('**/') ? source : `${PATH_SEPARATOR_SOURCE}(?:${source})`;
|
|
3060
|
+
const excludePatternsToRegExpSources = (patterns)=>{
|
|
3061
|
+
const sources = patterns.map((pattern)=>{
|
|
3062
|
+
const normalizedPattern = normalizeExcludePatternForRegExp(pattern);
|
|
3063
|
+
const regex = globToRegexp(normalizedPattern);
|
|
3064
|
+
let source = regex.source;
|
|
3065
|
+
if (source.startsWith('^')) source = source.substring(1);
|
|
3066
|
+
if (source.endsWith('$')) source = source.substring(0, source.length - 1);
|
|
3067
|
+
source = replacePathSeparatorsInRegExpSource(source);
|
|
3068
|
+
const isAbsolute = isAbsolutePatternForRegExp(normalizedPattern);
|
|
3069
|
+
const absolute = normalizedPattern.startsWith('./') ? source.substring(2) : source;
|
|
3070
|
+
return {
|
|
3071
|
+
relative: isAbsolute ? source : createRelativeContextExcludeSource(source, normalizedPattern),
|
|
3072
|
+
absolute: isAbsolute ? absolute : createProjectAbsoluteExcludeSource(absolute, normalizedPattern),
|
|
3073
|
+
isAbsolute
|
|
3074
|
+
};
|
|
3075
|
+
});
|
|
3076
|
+
if (0 === sources.length) return null;
|
|
3077
|
+
return sources;
|
|
3078
|
+
};
|
|
3079
|
+
const createBrowserContextExcludeRegExp = (patterns, projectRoot)=>{
|
|
3080
|
+
const excludeSources = excludePatternsToRegExpSources(patterns);
|
|
3081
|
+
if (!excludeSources) return null;
|
|
3082
|
+
const normalizedProjectRoot = normalizePathForRegExp(projectRoot).replace(/[\\/]$/, '');
|
|
3083
|
+
const projectRootSource = normalizedProjectRoot.split('/').map(escapeRegExp).join(PATH_SEPARATOR_SOURCE);
|
|
3084
|
+
const relativeExcludeSources = excludeSources.filter((source)=>!source.isAbsolute);
|
|
3085
|
+
const absoluteExcludeSources = excludeSources.filter((source)=>source.isAbsolute);
|
|
3086
|
+
const sourceBranches = [];
|
|
3087
|
+
if (relativeExcludeSources.length > 0) {
|
|
3088
|
+
const relativePatternSource = `(?:${relativeExcludeSources.map((source)=>source.relative).join('|')})`;
|
|
3089
|
+
const absolutePatternSource = `(?:${relativeExcludeSources.map((source)=>source.absolute).join('|')})`;
|
|
3090
|
+
const relativeSource = `(?:${relativePatternSource})`;
|
|
3091
|
+
const absoluteSource = normalizedProjectRoot ? `${projectRootSource}(?=${PATH_SEPARATOR_SOURCE})(?:${absolutePatternSource})` : `(?:${absolutePatternSource})`;
|
|
3092
|
+
sourceBranches.push(`(?!${WINDOWS_ABSOLUTE_PATH_SOURCE}|${PATH_SEPARATOR_SOURCE})${relativeSource}`, absoluteSource);
|
|
3036
3093
|
}
|
|
3037
|
-
if (0
|
|
3038
|
-
return new RegExp(
|
|
3094
|
+
if (absoluteExcludeSources.length > 0) sourceBranches.push(`(?:${absoluteExcludeSources.map((source)=>source.relative).join('|')})`);
|
|
3095
|
+
return new RegExp(`^(?:${sourceBranches.join('|')})$`);
|
|
3039
3096
|
};
|
|
3040
3097
|
const findTestFileInModules = (modules, entryTestFiles)=>{
|
|
3041
3098
|
if (!modules) return null;
|
|
@@ -3211,7 +3268,7 @@ const generateManifestModule = ({ manifestPath, entries })=>{
|
|
|
3211
3268
|
const projectRootPosix = normalize(project.rootPath);
|
|
3212
3269
|
const includeRegExp = globPatternsToRegExp(project.normalizedConfig.include);
|
|
3213
3270
|
const excludePatterns = project.normalizedConfig.exclude.patterns;
|
|
3214
|
-
const excludeRegExp =
|
|
3271
|
+
const excludeRegExp = createBrowserContextExcludeRegExp(excludePatterns, projectRootPosix);
|
|
3215
3272
|
lines.push(`const ${varName} = import.meta.webpackContext(${JSON.stringify(projectRootPosix)}, {`);
|
|
3216
3273
|
lines.push(' recursive: true,');
|
|
3217
3274
|
lines.push(` regExp: ${includeRegExp.toString()},`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rstest/browser",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.6",
|
|
4
4
|
"description": "Browser mode support for Rstest testing framework.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rstest",
|
|
@@ -48,21 +48,21 @@
|
|
|
48
48
|
"ws": "^8.21.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@rslib/core": "0.
|
|
51
|
+
"@rslib/core": "0.23.0",
|
|
52
52
|
"@types/convert-source-map": "^2.0.3",
|
|
53
53
|
"@types/picomatch": "^4.0.3",
|
|
54
54
|
"@types/ws": "^8.18.1",
|
|
55
55
|
"@vitest/snapshot": "^3.2.6",
|
|
56
56
|
"birpc": "^4.0.0",
|
|
57
57
|
"picomatch": "^4.0.4",
|
|
58
|
-
"playwright": "^1.
|
|
58
|
+
"playwright": "^1.61.0",
|
|
59
59
|
"@rstest/browser-ui": "0.0.0",
|
|
60
|
-
"@rstest/
|
|
61
|
-
"@rstest/
|
|
60
|
+
"@rstest/tsconfig": "0.0.1",
|
|
61
|
+
"@rstest/core": "0.10.6"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"playwright": "^1.49.1",
|
|
65
|
-
"@rstest/core": "^0.10.
|
|
65
|
+
"@rstest/core": "^0.10.6"
|
|
66
66
|
},
|
|
67
67
|
"peerDependenciesMeta": {
|
|
68
68
|
"playwright": {
|
package/src/hostController.ts
CHANGED
|
@@ -629,6 +629,7 @@ const globToRegexp = (glob: string): RegExp => {
|
|
|
629
629
|
fastpaths: false,
|
|
630
630
|
noglobstar: false,
|
|
631
631
|
bash: false,
|
|
632
|
+
dot: true,
|
|
632
633
|
});
|
|
633
634
|
|
|
634
635
|
if (!regex) {
|
|
@@ -676,44 +677,189 @@ const globPatternsToRegExp = (patterns: string[]): RegExp => {
|
|
|
676
677
|
return new RegExp(`(?:${regexParts.join('|')})$`);
|
|
677
678
|
};
|
|
678
679
|
|
|
680
|
+
const REGEXP_SPECIAL_CHARACTERS = /[|\\{}()[\]^$+*?.]/g;
|
|
681
|
+
const PATH_SEPARATOR_SOURCE = String.raw`[\\/]`;
|
|
682
|
+
const WINDOWS_ABSOLUTE_PATH_SOURCE = String.raw`[A-Za-z]:[\\/]`;
|
|
683
|
+
|
|
684
|
+
const escapeRegExp = (value: string): string =>
|
|
685
|
+
value.replace(REGEXP_SPECIAL_CHARACTERS, '\\$&');
|
|
686
|
+
|
|
687
|
+
const normalizePathForRegExp = (value: string): string =>
|
|
688
|
+
normalize(value).replaceAll('\\', '/');
|
|
689
|
+
|
|
690
|
+
const normalizeExcludePatternForRegExp = (value: string): string =>
|
|
691
|
+
value.startsWith('./')
|
|
692
|
+
? `./${normalizePathForRegExp(value.substring(2))}`
|
|
693
|
+
: normalizePathForRegExp(value);
|
|
694
|
+
|
|
695
|
+
const isAbsolutePatternForRegExp = (value: string): boolean =>
|
|
696
|
+
value.startsWith('/') || /^[A-Za-z]:\//.test(value);
|
|
697
|
+
|
|
698
|
+
const isEscapedRegExpCharacter = (source: string, index: number): boolean => {
|
|
699
|
+
let backslashCount = 0;
|
|
700
|
+
for (
|
|
701
|
+
let current = index - 1;
|
|
702
|
+
current >= 0 && source[current] === '\\';
|
|
703
|
+
current--
|
|
704
|
+
) {
|
|
705
|
+
backslashCount++;
|
|
706
|
+
}
|
|
707
|
+
return backslashCount % 2 === 1;
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
const replacePathSeparatorsInRegExpSource = (source: string): string => {
|
|
711
|
+
let result = '';
|
|
712
|
+
let inCharacterClass = false;
|
|
713
|
+
|
|
714
|
+
for (let index = 0; index < source.length; index++) {
|
|
715
|
+
const character = source[index];
|
|
716
|
+
const isEscaped = isEscapedRegExpCharacter(source, index);
|
|
717
|
+
|
|
718
|
+
if (character === '[' && !isEscaped) {
|
|
719
|
+
inCharacterClass = true;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
if (!inCharacterClass && character === '\\' && source[index + 1] === '/') {
|
|
723
|
+
result += PATH_SEPARATOR_SOURCE;
|
|
724
|
+
index++;
|
|
725
|
+
continue;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
result += character;
|
|
729
|
+
|
|
730
|
+
if (character === ']' && !isEscaped) {
|
|
731
|
+
inCharacterClass = false;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
return result;
|
|
736
|
+
};
|
|
737
|
+
|
|
738
|
+
type BrowserContextExcludeSource = {
|
|
739
|
+
relative: string;
|
|
740
|
+
absolute: string;
|
|
741
|
+
isAbsolute: boolean;
|
|
742
|
+
};
|
|
743
|
+
|
|
744
|
+
const createRelativeContextExcludeSource = (
|
|
745
|
+
source: string,
|
|
746
|
+
normalizedPattern: string,
|
|
747
|
+
): string => {
|
|
748
|
+
if (normalizedPattern.startsWith('./')) {
|
|
749
|
+
return source;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
return normalizedPattern.startsWith('**/')
|
|
753
|
+
? `(?:(?:${source})|\\.(?:${source}))`
|
|
754
|
+
: `(?:(?:${source})|\\.${PATH_SEPARATOR_SOURCE}(?:${source}))`;
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
const createProjectAbsoluteExcludeSource = (
|
|
758
|
+
source: string,
|
|
759
|
+
normalizedPattern: string,
|
|
760
|
+
): string =>
|
|
761
|
+
normalizedPattern.startsWith('./') || normalizedPattern.startsWith('**/')
|
|
762
|
+
? source
|
|
763
|
+
: `${PATH_SEPARATOR_SOURCE}(?:${source})`;
|
|
764
|
+
|
|
679
765
|
/**
|
|
680
766
|
* Convert exclude patterns to a RegExp for import.meta.webpackContext's exclude option
|
|
681
767
|
* This is used at compile time to filter out files during bundling
|
|
682
768
|
*
|
|
683
769
|
* Example:
|
|
684
770
|
* Input: ['**\/node_modules\/**', '**\/dist\/**']
|
|
685
|
-
* Output:
|
|
771
|
+
* Output: a regexp matching node_modules or dist path segments.
|
|
686
772
|
*/
|
|
687
|
-
const
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
);
|
|
697
|
-
if (match) {
|
|
698
|
-
// Handle {a,b,c} patterns
|
|
699
|
-
const parts = match[1]!.split(',');
|
|
700
|
-
for (const part of parts) {
|
|
701
|
-
// Clean up the part (remove leading dots for hidden dirs)
|
|
702
|
-
const cleaned = part.replace(/^\./, '');
|
|
703
|
-
if (cleaned && !keywords.includes(cleaned)) {
|
|
704
|
-
keywords.push(cleaned);
|
|
705
|
-
}
|
|
706
|
-
}
|
|
773
|
+
const excludePatternsToRegExpSources = (
|
|
774
|
+
patterns: string[],
|
|
775
|
+
): BrowserContextExcludeSource[] | null => {
|
|
776
|
+
const sources = patterns.map((pattern) => {
|
|
777
|
+
const normalizedPattern = normalizeExcludePatternForRegExp(pattern);
|
|
778
|
+
const regex = globToRegexp(normalizedPattern);
|
|
779
|
+
let source = regex.source;
|
|
780
|
+
if (source.startsWith('^')) {
|
|
781
|
+
source = source.substring(1);
|
|
707
782
|
}
|
|
783
|
+
if (source.endsWith('$')) {
|
|
784
|
+
source = source.substring(0, source.length - 1);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
source = replacePathSeparatorsInRegExpSource(source);
|
|
788
|
+
const isAbsolute = isAbsolutePatternForRegExp(normalizedPattern);
|
|
789
|
+
const absolute = normalizedPattern.startsWith('./')
|
|
790
|
+
? source.substring(2)
|
|
791
|
+
: source;
|
|
792
|
+
|
|
793
|
+
return {
|
|
794
|
+
relative: isAbsolute
|
|
795
|
+
? source
|
|
796
|
+
: createRelativeContextExcludeSource(source, normalizedPattern),
|
|
797
|
+
absolute: isAbsolute
|
|
798
|
+
? absolute
|
|
799
|
+
: createProjectAbsoluteExcludeSource(absolute, normalizedPattern),
|
|
800
|
+
isAbsolute,
|
|
801
|
+
};
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
if (sources.length === 0) {
|
|
805
|
+
return null;
|
|
708
806
|
}
|
|
709
807
|
|
|
710
|
-
|
|
808
|
+
return sources;
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
export const createBrowserContextExcludeRegExp = (
|
|
812
|
+
patterns: string[],
|
|
813
|
+
projectRoot: string,
|
|
814
|
+
): RegExp | null => {
|
|
815
|
+
const excludeSources = excludePatternsToRegExpSources(patterns);
|
|
816
|
+
if (!excludeSources) {
|
|
711
817
|
return null;
|
|
712
818
|
}
|
|
713
819
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
820
|
+
const normalizedProjectRoot = normalizePathForRegExp(projectRoot).replace(
|
|
821
|
+
/[\\/]$/,
|
|
822
|
+
'',
|
|
823
|
+
);
|
|
824
|
+
const projectRootSource = normalizedProjectRoot
|
|
825
|
+
.split('/')
|
|
826
|
+
.map(escapeRegExp)
|
|
827
|
+
.join(PATH_SEPARATOR_SOURCE);
|
|
828
|
+
const relativeExcludeSources = excludeSources.filter(
|
|
829
|
+
(source) => !source.isAbsolute,
|
|
830
|
+
);
|
|
831
|
+
const absoluteExcludeSources = excludeSources.filter(
|
|
832
|
+
(source) => source.isAbsolute,
|
|
833
|
+
);
|
|
834
|
+
const sourceBranches: string[] = [];
|
|
835
|
+
|
|
836
|
+
if (relativeExcludeSources.length > 0) {
|
|
837
|
+
const relativePatternSource = `(?:${relativeExcludeSources
|
|
838
|
+
.map((source) => source.relative)
|
|
839
|
+
.join('|')})`;
|
|
840
|
+
const absolutePatternSource = `(?:${relativeExcludeSources
|
|
841
|
+
.map((source) => source.absolute)
|
|
842
|
+
.join('|')})`;
|
|
843
|
+
const relativeSource = `(?:${relativePatternSource})`;
|
|
844
|
+
const absoluteSource = normalizedProjectRoot
|
|
845
|
+
? `${projectRootSource}(?=${PATH_SEPARATOR_SOURCE})(?:${absolutePatternSource})`
|
|
846
|
+
: `(?:${absolutePatternSource})`;
|
|
847
|
+
|
|
848
|
+
sourceBranches.push(
|
|
849
|
+
`(?!${WINDOWS_ABSOLUTE_PATH_SOURCE}|${PATH_SEPARATOR_SOURCE})${relativeSource}`,
|
|
850
|
+
absoluteSource,
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
if (absoluteExcludeSources.length > 0) {
|
|
855
|
+
sourceBranches.push(
|
|
856
|
+
`(?:${absoluteExcludeSources
|
|
857
|
+
.map((source) => source.relative)
|
|
858
|
+
.join('|')})`,
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
return new RegExp(`^(?:${sourceBranches.join('|')})$`);
|
|
717
863
|
};
|
|
718
864
|
|
|
719
865
|
type StatsModule = {
|
|
@@ -1087,7 +1233,10 @@ const generateManifestModule = ({
|
|
|
1087
1233
|
project.normalizedConfig.include,
|
|
1088
1234
|
);
|
|
1089
1235
|
const excludePatterns = project.normalizedConfig.exclude.patterns;
|
|
1090
|
-
const excludeRegExp =
|
|
1236
|
+
const excludeRegExp = createBrowserContextExcludeRegExp(
|
|
1237
|
+
excludePatterns,
|
|
1238
|
+
projectRootPosix,
|
|
1239
|
+
);
|
|
1091
1240
|
|
|
1092
1241
|
lines.push(
|
|
1093
1242
|
`const ${varName} = import.meta.webpackContext(${JSON.stringify(projectRootPosix)}, {`,
|