@thinkwise/testwise 0.2.0-beta.0 → 0.2.0-beta.22
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/Testwise.ts +7 -4
- package/artifact-builder/ArtifactManager.ts +0 -1
- package/artifact-builder/InterfaceGenerator.ts +65 -83
- package/artifact-builder/ModelDataBuilder.ts +50 -33
- package/artifact-builder/ModelDataRefiner.ts +10 -9
- package/artifact-builder/SchemaGenerator.ts +1 -4
- package/artifact-builder/ScreenInterfaceRefiner.ts +0 -5
- package/artifact-builder/SubjectGenerator.ts +2 -2
- package/artifact-builder/SubjectRegistration.ts +0 -5
- package/artifact-builder/helpers/DataRetriever.ts +2 -2
- package/artifact-builder/helpers/NamingHandler.ts +3 -1
- package/artifact-builder/helpers/Stopwatch.ts +13 -0
- package/artifact-builder/helpers/index.ts +1 -0
- package/dist/Testwise.d.ts +1 -0
- package/dist/Testwise.js +16 -5
- package/dist/Testwise.js.map +1 -1
- package/dist/artifact-builder/ArtifactManager.js.map +1 -1
- package/dist/artifact-builder/InterfaceGenerator.d.ts +0 -1
- package/dist/artifact-builder/InterfaceGenerator.js +55 -67
- package/dist/artifact-builder/InterfaceGenerator.js.map +1 -1
- package/dist/artifact-builder/ModelDataBuilder.js +26 -13
- package/dist/artifact-builder/ModelDataBuilder.js.map +1 -1
- package/dist/artifact-builder/ModelDataRefiner.js +3 -3
- package/dist/artifact-builder/ModelDataRefiner.js.map +1 -1
- package/dist/artifact-builder/SchemaGenerator.js +0 -2
- package/dist/artifact-builder/SchemaGenerator.js.map +1 -1
- package/dist/artifact-builder/ScreenInterfaceRefiner.js +0 -5
- package/dist/artifact-builder/ScreenInterfaceRefiner.js.map +1 -1
- package/dist/artifact-builder/SubjectGenerator.js.map +1 -1
- package/dist/artifact-builder/SubjectRegistration.d.ts +0 -1
- package/dist/artifact-builder/SubjectRegistration.js +0 -1
- package/dist/artifact-builder/SubjectRegistration.js.map +1 -1
- package/dist/artifact-builder/helpers/DataRetriever.js +2 -2
- package/dist/artifact-builder/helpers/DataRetriever.js.map +1 -1
- package/dist/artifact-builder/helpers/NamingHandler.js +3 -1
- package/dist/artifact-builder/helpers/NamingHandler.js.map +1 -1
- package/dist/artifact-builder/helpers/Stopwatch.d.ts +5 -0
- package/dist/artifact-builder/helpers/Stopwatch.js +13 -0
- package/dist/artifact-builder/helpers/Stopwatch.js.map +1 -0
- package/dist/artifact-builder/helpers/index.d.ts +1 -0
- package/dist/artifact-builder/helpers/index.js +1 -0
- package/dist/artifact-builder/helpers/index.js.map +1 -1
- package/enums/ElementTypes.ts +1 -1
- package/interfaces/IRegisteredSubjects.ts +1 -1
- package/package.json +4 -3
- package/scripts/main.js +84 -82
- package/scripts/postinstall.js +4 -7
- package/scripts/setup.js +37 -37
- package/scripts/sync.js +56 -23
- package/services/ConfigBuilder.ts +1 -1
- package/types/Components.ts +1 -1
package/Testwise.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { test as base } from '@playwright/test';
|
|
2
|
+
import { test as bddBase } from 'playwright-bdd';
|
|
2
3
|
import { Components, GoToDeepLink, LoginFeatures, UserSimulation } from './page-extensions/index.js';
|
|
3
4
|
import { SubjectProvider } from './page-extensions/SubjectProvider.js';
|
|
4
5
|
import { SubjectRegistry } from './page-extensions/SubjectRegistry.js';
|
|
@@ -11,9 +12,7 @@ function combineExtensions(baseTest: Test, ...extensions: { new (test: Test): {
|
|
|
11
12
|
return extensions.reduce((test, Extension) => new Extension(test).test, baseTest);
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
base,
|
|
16
|
-
|
|
15
|
+
const extensions = [
|
|
17
16
|
// Override section
|
|
18
17
|
ClickOverride,
|
|
19
18
|
FillOverride,
|
|
@@ -26,4 +25,8 @@ export const test: Test = combineExtensions(
|
|
|
26
25
|
WaitEventHandler,
|
|
27
26
|
SubjectRegistry,
|
|
28
27
|
SubjectProvider
|
|
29
|
-
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
export const test: Test = combineExtensions(base, ...extensions);
|
|
31
|
+
|
|
32
|
+
export const bddTest: Test = combineExtensions(bddBase, ...extensions);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import { exec } from 'node:child_process';
|
|
3
1
|
import fs from 'node:fs';
|
|
4
2
|
import path from 'node:path';
|
|
5
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import * as prettier from 'prettier';
|
|
5
|
+
import { FetchingJSONSchemaStore, InputData, JSONSchemaInput, quicktype } from 'quicktype-core';
|
|
6
6
|
import { PathResolver } from '../helpers/PathResolver.js';
|
|
7
7
|
import { NamingHandler } from '../index.js';
|
|
8
8
|
|
|
@@ -24,7 +24,6 @@ export class InterfaceGenerator {
|
|
|
24
24
|
const schemasDirectory = this.getScreenSchemaFilesPath();
|
|
25
25
|
|
|
26
26
|
await this.generateInterfacesFromSchemaFiles(schemasDirectory, SchemaType.Screen, screenOutputDirectory);
|
|
27
|
-
await this.runPrettierOnSpecifiedDirectory(screenOutputDirectory);
|
|
28
27
|
|
|
29
28
|
console.info('All screen schemas processed.');
|
|
30
29
|
}
|
|
@@ -37,21 +36,18 @@ export class InterfaceGenerator {
|
|
|
37
36
|
this.verifyOutputDirectory(subjectOutputDirectory);
|
|
38
37
|
|
|
39
38
|
await this.generateInterfacesFromSchemaFiles(schemasDirectory, SchemaType.Subject, subjectOutputDirectory);
|
|
40
|
-
await this.runPrettierOnSpecifiedDirectory(subjectOutputDirectory);
|
|
41
39
|
|
|
42
40
|
console.info('All subject schemas processed.');
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
private verifyGeneratedSubjectSchemasDirectory(directory: string) {
|
|
46
44
|
if (!fs.existsSync(directory)) {
|
|
47
|
-
console.error(`Schemas directory not found: ${directory}`);
|
|
48
45
|
return;
|
|
49
46
|
}
|
|
50
47
|
}
|
|
51
48
|
|
|
52
49
|
private verifyOutputDirectory(directory: string) {
|
|
53
50
|
if (!fs.existsSync(directory)) {
|
|
54
|
-
console.info(`Creating output directory: ${directory}`);
|
|
55
51
|
fs.mkdirSync(directory, { recursive: true });
|
|
56
52
|
}
|
|
57
53
|
}
|
|
@@ -69,51 +65,58 @@ export class InterfaceGenerator {
|
|
|
69
65
|
return componentsDirectory;
|
|
70
66
|
}
|
|
71
67
|
|
|
72
|
-
private createInterfaceFromSchema(
|
|
68
|
+
private async createInterfaceFromSchema(
|
|
73
69
|
schemasDirectory: string,
|
|
74
70
|
outputPath: string,
|
|
75
71
|
file: string,
|
|
76
72
|
isInterface: boolean = false
|
|
77
73
|
): Promise<boolean> {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
})
|
|
74
|
+
try {
|
|
75
|
+
const baseFileName = file.slice(0, file.lastIndexOf('.'));
|
|
76
|
+
const correctInterfaceName = isInterface
|
|
77
|
+
? this._namingHandler.generateScreenInterfaceName(baseFileName)
|
|
78
|
+
: this._namingHandler.snakeToPascalCase(baseFileName);
|
|
79
|
+
|
|
80
|
+
const schemaPath = path.join(schemasDirectory, file);
|
|
81
|
+
const schemaContent = fs.readFileSync(schemaPath, 'utf-8');
|
|
82
|
+
|
|
83
|
+
const schemaInput = new JSONSchemaInput(new FetchingJSONSchemaStore());
|
|
84
|
+
await schemaInput.addSource({
|
|
85
|
+
name: correctInterfaceName,
|
|
86
|
+
schema: schemaContent
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const inputData = new InputData();
|
|
90
|
+
inputData.addInput(schemaInput);
|
|
91
|
+
|
|
92
|
+
const result = await quicktype({
|
|
93
|
+
inputData,
|
|
94
|
+
lang: 'typescript',
|
|
95
|
+
rendererOptions: { 'just-types': 'true', 'nice-property-names': 'true' }
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
let updatedContent = result.lines.join('\n');
|
|
99
|
+
|
|
100
|
+
updatedContent = updatedContent.replace(/interface\s+\w+/, `interface ${correctInterfaceName}`);
|
|
101
|
+
|
|
102
|
+
const formattedContent = await prettier.format(updatedContent, {
|
|
103
|
+
parser: 'typescript',
|
|
104
|
+
singleQuote: true,
|
|
105
|
+
semi: true,
|
|
106
|
+
trailingComma: 'all'
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
fs.writeFileSync(outputPath, formattedContent, 'utf-8');
|
|
110
|
+
|
|
111
|
+
return true;
|
|
112
|
+
} catch (error) {
|
|
113
|
+
if (error instanceof Error) {
|
|
114
|
+
console.error(`Error processing ${file}:`, error.message);
|
|
115
|
+
} else {
|
|
116
|
+
console.error(`Error processing ${file}:`, error);
|
|
117
|
+
}
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
117
120
|
}
|
|
118
121
|
|
|
119
122
|
private async generateInterfacesFromSchemaFiles(
|
|
@@ -123,46 +126,25 @@ export class InterfaceGenerator {
|
|
|
123
126
|
): Promise<void> {
|
|
124
127
|
const schemaFiles: string[] = this.getGeneratedSubjectSchemas(schemasDirectory);
|
|
125
128
|
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
const fileName = this._namingHandler.getPascalSubjectComponentName(file);
|
|
129
|
-
|
|
130
|
-
if (schemaType === SchemaType.Subject) {
|
|
131
|
-
const subject = this._namingHandler.getSubjectFromFileName(fileName);
|
|
132
|
-
const componentsDirectory = this.verifySubjectComponentsDirectory(outputPath, subject);
|
|
133
|
-
const perFileOutputPath = path.join(componentsDirectory, `${fileName}.ts`);
|
|
134
|
-
this.createInterfaceFromSchema(schemasDirectory, perFileOutputPath, file).then(resolve).catch(reject);
|
|
135
|
-
} else if (schemaType === SchemaType.Screen) {
|
|
136
|
-
const perFileOutputPath = path.join(outputPath, `I${fileName}.ts`);
|
|
137
|
-
this.createInterfaceFromSchema(schemasDirectory, perFileOutputPath, file, true).then(resolve).catch(reject);
|
|
138
|
-
} else {
|
|
139
|
-
reject(new Error(`Unsupported schema type: ${schemaType}`));
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
});
|
|
129
|
+
const tasks = schemaFiles.map(async (file) => {
|
|
130
|
+
const fileName = this._namingHandler.getPascalSubjectComponentName(file);
|
|
143
131
|
|
|
144
|
-
|
|
145
|
-
|
|
132
|
+
if (schemaType === SchemaType.Subject) {
|
|
133
|
+
const subject = this._namingHandler.getSubjectFromFileName(fileName);
|
|
134
|
+
const componentsDirectory = this.verifySubjectComponentsDirectory(outputPath, subject);
|
|
135
|
+
const perFileOutputPath = path.join(componentsDirectory, `${fileName}.ts`);
|
|
136
|
+
return this.createInterfaceFromSchema(schemasDirectory, perFileOutputPath, file);
|
|
137
|
+
}
|
|
146
138
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
`npx prettier --write "${relativeDir}"`,
|
|
154
|
-
{ cwd: packageDir },
|
|
155
|
-
(prettierError) => {
|
|
156
|
-
if (prettierError) {
|
|
157
|
-
console.error(`Prettier failed for ${directory}:`, prettierError.message);
|
|
158
|
-
reject(prettierError);
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
console.info(`Formatted all files in: ${directory}`);
|
|
162
|
-
resolve(true);
|
|
163
|
-
}
|
|
164
|
-
);
|
|
139
|
+
if (schemaType === SchemaType.Screen) {
|
|
140
|
+
const perFileOutputPath = path.join(outputPath, `I${fileName}.ts`);
|
|
141
|
+
return this.createInterfaceFromSchema(schemasDirectory, perFileOutputPath, file, true);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
throw new Error(`Unsupported schema type: ${schemaType}`);
|
|
165
145
|
});
|
|
146
|
+
|
|
147
|
+
await Promise.all(tasks);
|
|
166
148
|
}
|
|
167
149
|
|
|
168
150
|
public getScreenSchemaFilesPath(): string {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
/** biome-ignore-all lint/style/noNonNullAssertion: Because I can */
|
|
3
3
|
/** biome-ignore-all lint/suspicious/noExplicitAny: Because I can */
|
|
4
|
+
import * as fs from 'node:fs/promises';
|
|
5
|
+
import * as path from 'node:path';
|
|
4
6
|
import axios from 'axios';
|
|
5
7
|
import type { IProperty } from '../interfaces/IProperty.js';
|
|
6
8
|
import { testwiseConfig } from '../services/ConfigBuilder.js';
|
|
@@ -37,23 +39,23 @@ export async function buildSubjects() {
|
|
|
37
39
|
|
|
38
40
|
const rawTabs: any[] = response.data?.value || [];
|
|
39
41
|
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
const subjects: Subjects[] = rawTabs
|
|
43
|
+
.flatMap((tab: any) => {
|
|
44
|
+
const base = {
|
|
45
|
+
subject: tab.tab_id,
|
|
46
|
+
variant: tab.tab_variant_id
|
|
47
|
+
};
|
|
45
48
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
return [
|
|
50
|
+
{ ...base, screentype_id: tab.main_screen_type_id, screentype_context: 'main' },
|
|
51
|
+
{ ...base, screentype_id: tab.detail_screen_type_id, screentype_context: 'detail' },
|
|
52
|
+
{ ...base, screentype_id: tab.zoom_screen_type_id, screentype_context: 'zoom' },
|
|
53
|
+
{ ...base, screentype_id: tab.popup_screen_type_id, screentype_context: 'popup' }
|
|
54
|
+
];
|
|
55
|
+
})
|
|
56
|
+
.filter((item) => item.screentype_id !== 'not_visible_in_gui');
|
|
53
57
|
|
|
54
|
-
const colResponse = await axiosInstance.get(
|
|
55
|
-
`/iam/${metaEndpoint}/i_ui_col?$filter=gui_appl_id%20eq%20${guiApplId}`
|
|
56
|
-
);
|
|
58
|
+
const colResponse = await axiosInstance.get(`/iam/${metaEndpoint}/i_ui_col?$filter=gui_appl_id%20eq%20${guiApplId}`);
|
|
57
59
|
|
|
58
60
|
const allProperties: IPropertyWithSubjectIdentifiers[] = colResponse.data?.value.map((col: any) => ({
|
|
59
61
|
subject: col.tab_id,
|
|
@@ -62,7 +64,7 @@ export async function buildSubjects() {
|
|
|
62
64
|
control_type: col.control_id || ''
|
|
63
65
|
}));
|
|
64
66
|
|
|
65
|
-
for (const subject of
|
|
67
|
+
for (const subject of subjects) {
|
|
66
68
|
const matchingProperties = allProperties.filter(
|
|
67
69
|
(prop) => prop.subject === subject.subject && prop.variant === subject.variant
|
|
68
70
|
);
|
|
@@ -71,18 +73,36 @@ export async function buildSubjects() {
|
|
|
71
73
|
subject.properties = matchingProperties.map(({ subject, variant, ...rest }) => rest);
|
|
72
74
|
}
|
|
73
75
|
|
|
74
|
-
const
|
|
76
|
+
const subjectsWithLookupsSet = await setLookupDropdowns(subjects);
|
|
75
77
|
|
|
76
|
-
const
|
|
77
|
-
const path = await import('node:path');
|
|
78
|
+
const seedDataDirectory = new DataRetriever().getSeedDataDirectory();
|
|
78
79
|
|
|
79
80
|
const seedDataPath = path.join(seedDataDirectory, 'subjects.json');
|
|
80
|
-
await fs.writeFile(seedDataPath, JSON.stringify(
|
|
81
|
+
await fs.writeFile(seedDataPath, JSON.stringify(subjectsWithLookupsSet, null, 2), 'utf-8');
|
|
81
82
|
console.log(`Seed data written to ${seedDataPath}`);
|
|
82
83
|
}
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
async function setLookupDropdowns(subjects: Subjects[]): Promise<Subjects[]> {
|
|
86
|
+
const response = await axiosInstance.get(
|
|
87
|
+
`/iam/${metaEndpoint}/i_ui_tab_look_up?$filter=gui_appl_id%20eq%20${guiApplId}`
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const lookupMappings: any[] = response.data?.value || [];
|
|
91
|
+
|
|
92
|
+
for (const mapping of lookupMappings) {
|
|
93
|
+
const targetSubject = subjects.find(
|
|
94
|
+
(subj) => subj.subject === mapping.tab_id && subj.variant === mapping.tab_variant_id
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const targetProperty = targetSubject?.properties?.find((prop) => prop.col === mapping.col_id);
|
|
98
|
+
|
|
99
|
+
if (targetProperty) {
|
|
100
|
+
targetProperty.control_type = 'LOOKUP_DROPDOWN';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return subjects;
|
|
105
|
+
}
|
|
86
106
|
|
|
87
107
|
export async function buildScreens() {
|
|
88
108
|
const response = await axiosInstance.get(
|
|
@@ -119,32 +139,29 @@ export async function buildScreens() {
|
|
|
119
139
|
|
|
120
140
|
for (const comp of screenData.Components) {
|
|
121
141
|
const type = comp.ScreenComponentType;
|
|
122
|
-
properties[comp.ScreenComponentId] = {
|
|
142
|
+
properties[comp.ScreenComponentId] = { $ref: `#/definitions/${type}` };
|
|
123
143
|
required.push(comp.ScreenComponentId);
|
|
124
144
|
usedTypes.add(type);
|
|
125
145
|
}
|
|
126
146
|
|
|
127
147
|
const schema = {
|
|
128
148
|
title: `I_${screenTypeId}`,
|
|
129
|
-
type:
|
|
149
|
+
type: 'object',
|
|
130
150
|
properties,
|
|
131
151
|
required,
|
|
132
152
|
additionalProperties: false,
|
|
133
153
|
definitions: Array.from(usedTypes).reduce((acc, type) => {
|
|
134
154
|
acc[type] = {
|
|
135
|
-
type:
|
|
136
|
-
properties: { temp: { type:
|
|
137
|
-
required: [
|
|
155
|
+
type: 'object',
|
|
156
|
+
properties: { temp: { type: 'string' } },
|
|
157
|
+
required: ['temp'],
|
|
138
158
|
additionalProperties: false
|
|
139
159
|
};
|
|
140
160
|
return acc;
|
|
141
161
|
}, {} as any)
|
|
142
162
|
};
|
|
143
163
|
|
|
144
|
-
await fs.writeFile(
|
|
145
|
-
path.join(outputDir, `${screenTypeId}.json`),
|
|
146
|
-
JSON.stringify(schema, null, 2)
|
|
147
|
-
);
|
|
164
|
+
await fs.writeFile(path.join(outputDir, `${screenTypeId}.json`), JSON.stringify(schema, null, 2));
|
|
148
165
|
}
|
|
149
166
|
console.log('Screen schemas generated successfully.');
|
|
150
167
|
}
|
|
@@ -157,7 +174,7 @@ async function getGuiApplId(): Promise<number> {
|
|
|
157
174
|
const guiAppl = response.data?.value.find((appl: any) => {
|
|
158
175
|
const currentAlias = appl?.gui_appl_alias?.toString();
|
|
159
176
|
const targetAlias = guiApplAlias?.toString();
|
|
160
|
-
|
|
177
|
+
|
|
161
178
|
return currentAlias === targetAlias;
|
|
162
179
|
});
|
|
163
180
|
|
|
@@ -174,4 +191,4 @@ async function getGuiApplId(): Promise<number> {
|
|
|
174
191
|
interface IPropertyWithSubjectIdentifiers extends IProperty {
|
|
175
192
|
subject: string;
|
|
176
193
|
variant: string;
|
|
177
|
-
}
|
|
194
|
+
}
|
|
@@ -8,20 +8,21 @@ export class ModelDataRefiner {
|
|
|
8
8
|
|
|
9
9
|
public run() {
|
|
10
10
|
const seedDataDir = this._dataRetriever.getSeedDataDirectory();
|
|
11
|
-
const registeredSubjects
|
|
11
|
+
const registeredSubjects: IRegisteredSubjects[] | null = this._dataRetriever.getRegisteredSubjects();
|
|
12
12
|
|
|
13
13
|
if (!registeredSubjects || registeredSubjects.length === 0) {
|
|
14
|
-
console.
|
|
14
|
+
console.info('No registered subjects found.');
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
const subjects = this._dataRetriever.getSubjectsSeedData();
|
|
19
19
|
|
|
20
|
-
const subjectsToBuild = subjects.filter(subject =>
|
|
21
|
-
registeredSubjects.some(
|
|
22
|
-
registered
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
const subjectsToBuild = subjects.filter((subject) =>
|
|
21
|
+
registeredSubjects.some(
|
|
22
|
+
(registered) =>
|
|
23
|
+
registered.subject === subject.subject &&
|
|
24
|
+
(registered.variant != null ? registered.variant === subject.variant : subject.variant === '') &&
|
|
25
|
+
registered.screen_type === subject.screentype_context
|
|
25
26
|
)
|
|
26
27
|
);
|
|
27
28
|
|
|
@@ -29,10 +30,10 @@ export class ModelDataRefiner {
|
|
|
29
30
|
fs.writeFileSync(subjectsToBuildPath, JSON.stringify(subjectsToBuild, null, 2));
|
|
30
31
|
console.log(`Created subjectsToBuild.json with ${subjectsToBuild.length} subjects.`);
|
|
31
32
|
|
|
32
|
-
const screensToBuild = Array.from(new Set(subjectsToBuild.map(subject => subject.screentype_id)));
|
|
33
|
+
const screensToBuild = Array.from(new Set(subjectsToBuild.map((subject) => subject.screentype_id)));
|
|
33
34
|
|
|
34
35
|
const screensToBuildPath = path.resolve(seedDataDir, 'screensToBuild.json');
|
|
35
36
|
fs.writeFileSync(screensToBuildPath, JSON.stringify(screensToBuild, null, 2));
|
|
36
37
|
console.log(`Created screensToBuild.json with ${screensToBuild.length} screens.`);
|
|
37
38
|
}
|
|
38
|
-
}
|
|
39
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
2
|
import * as fs from 'node:fs';
|
|
4
3
|
import * as path from 'node:path';
|
|
@@ -48,11 +47,9 @@ export class SchemaGenerator {
|
|
|
48
47
|
switch (component) {
|
|
49
48
|
case 'Form':
|
|
50
49
|
this.createComponentSchema(subject, 'Form');
|
|
51
|
-
console.log(`Generated Form schema for subject: ${subject.subject}`);
|
|
52
50
|
break;
|
|
53
51
|
case 'Grid':
|
|
54
52
|
this.createComponentSchema(subject, 'Grid');
|
|
55
|
-
console.log(`Generated Grid schema for subject: ${subject.subject}`);
|
|
56
53
|
break;
|
|
57
54
|
}
|
|
58
55
|
}
|
|
@@ -90,7 +87,7 @@ export class SchemaGenerator {
|
|
|
90
87
|
const interfaceName = `${subject.subject}_${componentType.toLowerCase()}`;
|
|
91
88
|
const schemasDir = path.join(currentDirname, '..', '..', 'dist/test-artifacts/schemas');
|
|
92
89
|
const fileName = `${this._namingHandler.snakeToPascalCase(interfaceName)}.json`;
|
|
93
|
-
|
|
90
|
+
|
|
94
91
|
if (fs.existsSync(path.join(schemasDir, fileName))) {
|
|
95
92
|
return;
|
|
96
93
|
}
|
|
@@ -13,8 +13,6 @@ export class ScreenInterfaceRefiner {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
public refine() {
|
|
16
|
-
console.log('Refining interfaces in:', this._screensDirectory);
|
|
17
|
-
|
|
18
16
|
const screenFiles = this.getAllScreenInterfaceFiles();
|
|
19
17
|
|
|
20
18
|
screenFiles.forEach((screenFile) => {
|
|
@@ -34,9 +32,6 @@ export class ScreenInterfaceRefiner {
|
|
|
34
32
|
this.formatContent(screen);
|
|
35
33
|
|
|
36
34
|
fs.writeFileSync(filePath, screen.content, 'utf-8');
|
|
37
|
-
console.log(`Refined interfaces in: ${screenFile}`);
|
|
38
|
-
} else {
|
|
39
|
-
console.log(`No additional interfaces to refine in: ${screenFile}`);
|
|
40
35
|
}
|
|
41
36
|
|
|
42
37
|
this.indexScreenInterface(screenFile);
|
|
@@ -57,7 +57,7 @@ export class SubjectGenerator {
|
|
|
57
57
|
const tsFiles = fs.readdirSync(subjectFolderPath).filter((file) => file.endsWith('.ts') && file !== 'index.ts');
|
|
58
58
|
const indexFile = path.join(subjectFolderPath, 'index.ts');
|
|
59
59
|
|
|
60
|
-
if(tsFiles.length === 0) return;
|
|
60
|
+
if (tsFiles.length === 0) return;
|
|
61
61
|
|
|
62
62
|
if (!fs.existsSync(indexFile)) {
|
|
63
63
|
fs.writeFileSync(indexFile, '', 'utf-8');
|
|
@@ -65,7 +65,7 @@ export class SubjectGenerator {
|
|
|
65
65
|
|
|
66
66
|
tsFiles.forEach((tsFile) => {
|
|
67
67
|
if (tsFile === 'index.ts') return;
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
const className = tsFile.replace('.ts', '');
|
|
70
70
|
exportLines.push(`export { ${className} } from './${className}.js';`);
|
|
71
71
|
});
|
|
@@ -10,17 +10,12 @@ export class SubjectRegistration {
|
|
|
10
10
|
private readonly _currentFilename: string;
|
|
11
11
|
private readonly _currentDirname: string;
|
|
12
12
|
private readonly _subjectTypePath: string;
|
|
13
|
-
private readonly _subjectsIndexDirectory: string;
|
|
14
13
|
private readonly _subjectBuilderPath: string;
|
|
15
14
|
|
|
16
15
|
constructor() {
|
|
17
16
|
this._currentFilename = fileURLToPath(import.meta.url);
|
|
18
17
|
this._currentDirname = dirname(this._currentFilename);
|
|
19
18
|
this._subjectTypePath = path.resolve(this._currentDirname, '../../page-extensions/SubjectRegistry.ts');
|
|
20
|
-
this._subjectsIndexDirectory = path.resolve(
|
|
21
|
-
this._currentDirname,
|
|
22
|
-
`../../${SubjectRegistration.SUBJECTS_RELATIVE_PATH}/index.ts`
|
|
23
|
-
);
|
|
24
19
|
this._subjectBuilderPath = path.resolve(this._currentDirname, '../../page-extensions/SubjectProvider.ts');
|
|
25
20
|
}
|
|
26
21
|
|
|
@@ -31,7 +31,7 @@ export class DataRetriever {
|
|
|
31
31
|
public getSubjectsToBuild(): ISubject[] {
|
|
32
32
|
const subjectsToBuildPath = path.join(this._consumerRootDirectory, 'seed-data/subjectsToBuild.json');
|
|
33
33
|
if (!fs.existsSync(subjectsToBuildPath)) {
|
|
34
|
-
console.
|
|
34
|
+
console.info(`subjectsToBuild.json not found at: ${subjectsToBuildPath}. Using all subjects as fallback.`);
|
|
35
35
|
|
|
36
36
|
return this.getSubjectsSeedData();
|
|
37
37
|
}
|
|
@@ -43,7 +43,7 @@ export class DataRetriever {
|
|
|
43
43
|
public getScreensToBuild(): string[] {
|
|
44
44
|
const screensToBuildPath = path.join(this._consumerRootDirectory, 'seed-data/screensToBuild.json');
|
|
45
45
|
if (!fs.existsSync(screensToBuildPath)) {
|
|
46
|
-
console.
|
|
46
|
+
console.info(`screensToBuild.json not found at: ${screensToBuildPath}. Using all screens as fallback.`);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
const json = fs.readFileSync(screensToBuildPath, 'utf-8');
|
|
@@ -25,7 +25,8 @@ export class NamingHandler {
|
|
|
25
25
|
Form: {
|
|
26
26
|
email: formDefaultSuffix,
|
|
27
27
|
phone_number: formDefaultSuffix,
|
|
28
|
-
suggestion_starts_with:
|
|
28
|
+
suggestion_starts_with: formDefaultSuffix,
|
|
29
|
+
lookup_dropdown: KnownElementTypes.Lookup,
|
|
29
30
|
checkbox: KnownElementTypes.Checkbox,
|
|
30
31
|
multiline: KnownElementTypes.Textarea,
|
|
31
32
|
combo: KnownElementTypes.Dropdown
|
|
@@ -34,6 +35,7 @@ export class NamingHandler {
|
|
|
34
35
|
email: gridDefaultSuffix,
|
|
35
36
|
phone_number: gridDefaultSuffix,
|
|
36
37
|
suggestion_starts_with: gridDefaultSuffix,
|
|
38
|
+
lookup_dropdown: gridDefaultSuffix,
|
|
37
39
|
checkbox: gridDefaultSuffix,
|
|
38
40
|
multiline: gridDefaultSuffix,
|
|
39
41
|
combo: gridDefaultSuffix
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { performance } from 'node:perf_hooks';
|
|
2
|
+
|
|
3
|
+
export class Stopwatch {
|
|
4
|
+
start(message: string) {
|
|
5
|
+
const startTime = performance.now();
|
|
6
|
+
return {
|
|
7
|
+
stop() {
|
|
8
|
+
const duration = ((performance.now() - startTime) / 1000).toFixed(3);
|
|
9
|
+
console.log(`[${duration}s]: ${message}`);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
}
|
package/dist/Testwise.d.ts
CHANGED
package/dist/Testwise.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { test as base } from '@playwright/test';
|
|
2
|
+
import { test as bddBase } from 'playwright-bdd';
|
|
2
3
|
import { Components, GoToDeepLink, LoginFeatures, UserSimulation } from './page-extensions/index.js';
|
|
3
4
|
import { SubjectProvider } from './page-extensions/SubjectProvider.js';
|
|
4
5
|
import { SubjectRegistry } from './page-extensions/SubjectRegistry.js';
|
|
@@ -8,9 +9,19 @@ import { FillOverride } from './page-overrides/FillOverride.js';
|
|
|
8
9
|
function combineExtensions(baseTest, ...extensions) {
|
|
9
10
|
return extensions.reduce((test, Extension) => new Extension(test).test, baseTest);
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
-
// Override section
|
|
13
|
-
ClickOverride,
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
const extensions = [
|
|
13
|
+
// Override section
|
|
14
|
+
ClickOverride,
|
|
15
|
+
FillOverride,
|
|
16
|
+
// Extend section
|
|
17
|
+
Components,
|
|
18
|
+
GoToDeepLink,
|
|
19
|
+
LoginFeatures,
|
|
20
|
+
UserSimulation,
|
|
21
|
+
WaitEventHandler,
|
|
22
|
+
SubjectRegistry,
|
|
23
|
+
SubjectProvider
|
|
24
|
+
];
|
|
25
|
+
export const test = combineExtensions(base, ...extensions);
|
|
26
|
+
export const bddTest = combineExtensions(bddBase, ...extensions);
|
|
16
27
|
//# sourceMappingURL=Testwise.js.map
|
package/dist/Testwise.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Testwise.js","sourceRoot":"","sources":["../Testwise.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACrG,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAGhE,SAAS,iBAAiB,CAAC,QAAc,EAAE,GAAG,UAAkD;IAC9F,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACpF,CAAC;AAED,MAAM,
|
|
1
|
+
{"version":3,"file":"Testwise.js","sourceRoot":"","sources":["../Testwise.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACrG,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAGhE,SAAS,iBAAiB,CAAC,QAAc,EAAE,GAAG,UAAkD;IAC9F,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,GAAG;IACjB,mBAAmB;IACnB,aAAa;IACb,YAAY;IAEZ,iBAAiB;IACjB,UAAU;IACV,YAAY;IACZ,aAAa;IACb,cAAc;IACd,gBAAgB;IAChB,eAAe;IACf,eAAe;CAChB,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAAS,iBAAiB,CAAC,IAAI,EAAE,GAAG,UAAU,CAAC,CAAC;AAEjE,MAAM,CAAC,MAAM,OAAO,GAAS,iBAAiB,CAAC,OAAO,EAAE,GAAG,UAAU,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArtifactManager.js","sourceRoot":"","sources":["../../artifact-builder/ArtifactManager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ArtifactManager.js","sourceRoot":"","sources":["../../artifact-builder/ArtifactManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,OAAO,eAAe;IAI1B;QACE,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACzC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,gBAAgB,CAAC,CAAC;QACzF,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,gBAAgB,CAAC,CAAC;IAC5E,CAAC;IAED,aAAa;QACX,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;YACtC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9D,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAED,YAAY;QACV,OAAO,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACzC,CAAC;IAED,aAAa;QACX,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YACpC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAChE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;CACF"}
|