@@ -7,6 +7,7 @@ const { pascalCase } = require('change-case');
7
7
const { default : convertToSelectorUtil } = require ( '@cloudscape-design/test-utils-converter' ) ;
8
8
const { through, task } = require ( '../utils/gulp-utils' ) ;
9
9
const { writeFile, listPublicItems } = require ( '../utils/files' ) ;
10
+ const { pluralizeComponentName } = require ( '../utils/pluralize' ) ;
10
11
const themes = require ( '../utils/themes' ) ;
11
12
12
13
function toWrapper ( componentClass ) {
@@ -15,24 +16,92 @@ function toWrapper(componentClass) {
15
16
16
17
const testUtilsSrcDir = path . resolve ( 'src/test-utils' ) ;
17
18
const configs = {
19
+ common : {
20
+ buildFinder : ( { componentName, componentNamePlural } ) => `
21
+ ElementWrapper.prototype.find${ componentName } = function(selector) {
22
+ const rootSelector = \`.$\{${ toWrapper ( componentName ) } .rootSelector}\`;
23
+ // casting to 'any' is needed to avoid this issue with generics
24
+ // https://github.com/microsoft/TypeScript/issues/29132
25
+ return (this as any).findComponent(selector ? appendSelector(selector, rootSelector) : rootSelector, ${ toWrapper ( componentName ) } );
26
+ };
27
+
28
+ ElementWrapper.prototype.findAll${ componentNamePlural } = function(selector) {
29
+ return this.findAllComponents(${ toWrapper ( componentName ) } , selector);
30
+ };` ,
31
+ } ,
18
32
dom : {
19
33
defaultExport : `export default function wrapper(root: Element = document.body) { if (document && document.body && !document.body.contains(root)) { console.warn('[AwsUi] [test-utils] provided element is not part of the document body, interactions may work incorrectly')}; return new ElementWrapper(root); }` ,
20
- buildFinderInterface : ( { componentName } ) =>
21
- `find${ componentName } (selector?: string): ${ toWrapper ( componentName ) } | null;` ,
34
+ buildFinderInterface : ( { componentName, componentNamePlural } ) => `
35
+ /**
36
+ * Returns the wrapper of the first ${ componentName } that matches the specified CSS selector.
37
+ * If no CSS selector is specified, returns the wrapper of the first ${ componentName } .
38
+ * If no matching ${ componentName } is found, returns \`null\`.
39
+ *
40
+ * @param {string} [selector] CSS Selector
41
+ * @returns {${ toWrapper ( componentName ) } | null}
42
+ */
43
+ find${ componentName } (selector?: string): ${ toWrapper ( componentName ) } | null;
44
+
45
+ /**
46
+ * Returns an array of ${ componentName } wrapper that matches the specified CSS selector.
47
+ * If no CSS selector is specified, returns all of the ${ componentNamePlural } inside the current wrapper.
48
+ * If no matching ${ componentName } is found, returns an empty array.
49
+ *
50
+ * @param {string} [selector] CSS Selector
51
+ * @returns {Array<${ toWrapper ( componentName ) } >}
52
+ */
53
+ findAll${ componentNamePlural } (selector?: string): Array<${ toWrapper ( componentName ) } >;` ,
22
54
} ,
23
55
selectors : {
24
56
defaultExport : `export default function wrapper(root: string = 'body') { return new ElementWrapper(root); }` ,
25
- buildFinderInterface : ( { componentName } ) =>
26
- `find${ componentName } (selector?: string): ${ toWrapper ( componentName ) } ;` ,
57
+ buildFinderInterface : ( { componentName, componentNamePlural } ) => `
58
+ /**
59
+ * Returns a wrapper that matches the ${ componentNamePlural } with the specified CSS selector.
60
+ * If no CSS selector is specified, returns a wrapper that matches ${ componentNamePlural } .
61
+ *
62
+ * @param {string} [selector] CSS Selector
63
+ * @returns {${ toWrapper ( componentName ) } }
64
+ */
65
+ find${ componentName } (selector?: string): ${ toWrapper ( componentName ) } ;
66
+
67
+ /**
68
+ * Returns a multi-element wrapper that matches ${ componentNamePlural } with the specified CSS selector.
69
+ * If no CSS selector is specified, returns a multi-element wrapper that matches ${ componentNamePlural } .
70
+ *
71
+ * @param {string} [selector] CSS Selector
72
+ * @returns {MultiElementWrapper<${ toWrapper ( componentName ) } >}
73
+ */
74
+ findAll${ componentNamePlural } (selector?: string): MultiElementWrapper<${ toWrapper ( componentName ) } >;` ,
27
75
} ,
28
76
} ;
29
77
78
+ function generateFindersInterfaces ( { testUtilMetaData, testUtilType, configs } ) {
79
+ const { buildFinderInterface } = configs [ testUtilType ] ;
80
+ const findersInterfaces = testUtilMetaData . map ( buildFinderInterface ) ;
81
+
82
+ // we need to redeclare the interface in its original definition, extending a re-export will not work
83
+ // https://github.com/microsoft/TypeScript/issues/12607
84
+ const interfaces = `declare module '@cloudscape-design/test-utils-core/dist/${ testUtilType } ' {
85
+ interface ElementWrapper {
86
+ ${ findersInterfaces . join ( '\n' ) }
87
+ }
88
+ }` ;
89
+
90
+ return interfaces ;
91
+ }
92
+
93
+ function generateFindersImplementations ( { testUtilMetaData, configs } ) {
94
+ const { buildFinder } = configs . common ;
95
+ const findersImplementations = testUtilMetaData . map ( buildFinder ) ;
96
+
97
+ return findersImplementations . join ( '\n' ) ;
98
+ }
99
+
30
100
function generateIndexFileContent ( testUtilType , testUtilMetaData ) {
31
101
const config = configs [ testUtilType ] ;
32
102
if ( config === undefined ) {
33
103
throw new Error ( 'Unknown test util type' ) ;
34
104
}
35
- const { defaultExport, buildFinderInterface } = config ;
36
105
37
106
return [
38
107
// language=TypeScript
@@ -47,24 +116,9 @@ function generateIndexFileContent(testUtilType, testUtilMetaData) {
47
116
export { ${ componentName } Wrapper };
48
117
` ;
49
118
} ) ,
50
- // we need to redeclare the interface in its original definition, extending a re-export will not work
51
- // https://github.com/microsoft/TypeScript/issues/12607
52
- `declare module '@cloudscape-design/test-utils-core/dist/${ testUtilType } ' {
53
- interface ElementWrapper {
54
- ${ testUtilMetaData . map ( metaData => buildFinderInterface ( metaData ) ) . join ( '\n' ) }
55
- }
56
- }` ,
57
- ...testUtilMetaData . map ( ( { componentName } ) => {
58
- const wrapperName = toWrapper ( componentName ) ;
59
- // language=TypeScript
60
- return `ElementWrapper.prototype.find${ componentName } = function(selector) {
61
- const rootSelector = \`.$\{${ wrapperName } .rootSelector}\`;
62
- // casting to 'any' is needed to avoid this issue with generics
63
- // https://github.com/microsoft/TypeScript/issues/29132
64
- return (this as any).findComponent(selector ? appendSelector(selector, rootSelector) : rootSelector, ${ wrapperName } );
65
- };` ;
66
- } ) ,
67
- defaultExport ,
119
+ generateFindersInterfaces ( { testUtilMetaData, testUtilType, configs } ) ,
120
+ generateFindersImplementations ( { testUtilMetaData, configs } ) ,
121
+ config . defaultExport ,
68
122
] . join ( '\n' ) ;
69
123
}
70
124
@@ -77,9 +131,11 @@ function generateTestUtilMetaData(testUtilType) {
77
131
78
132
const componentNameKebab = componentFolderName ;
79
133
const componentName = pascalCase ( componentNameKebab ) ;
134
+ const componentNamePlural = pluralizeComponentName ( componentName ) ;
80
135
81
136
const componentMetaData = {
82
137
componentName,
138
+ componentNamePlural,
83
139
relPathtestUtilFile,
84
140
} ;
85
141
0 commit comments