Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Add fileExport capability #352

Merged
merged 12 commits into from
Dec 8, 2021

Conversation

sap-sebelao
Copy link
Member

@sap-sebelao sap-sebelao commented Oct 7, 2021

JIRA: CPOUI5FOUNDATION-425

- Some tools, such as Support Assistant, provide extra reports directly from tests
using a window._$files variable; this is no longer read anywhere and such reports are
currently unsupported
- See https://github.com/SAP/openui5/blob/master/src/sap.ui.core/src/sap/ui/core/support/RuleEngineOpaExtension.js#L243
- this adds mechanism to read and save these the variable as files using a custom reporter
with some additions to browser.js to 'send' the results as part of karma.complete argument
@CLAassistant
Copy link

CLAassistant commented Oct 7, 2021

CLA assistant check
All committers have signed the CLA.

@sap-sebelao sap-sebelao changed the title Add custom files read-send mechanism on complete Add custom files read-save mechanism on complete Oct 7, 2021
@coveralls
Copy link

coveralls commented Oct 7, 2021

Coverage Status

Coverage increased (+2.3%) to 55.26% when pulling a1b96f1 on sap-sebelao:qunitCustomFiles into 6e50872 on SAP:master.

@matz3 matz3 self-requested a review October 7, 2021 11:41
README.md Outdated Show resolved Hide resolved
@larskissel larskissel requested a review from KlattG November 30, 2021 15:37
Copy link

@KlattG KlattG left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few small suggestions. Otherwise LGTM

README.md Outdated
Type: `boolean` or `object`
Default: `false`

Configures whether report files provided by tools like the UI5 Support Assistant are exported to the file system.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Configures whether report files provided by tools like the UI5 Support Assistant are exported to the file system.
Configures whether report files provided by tools like UI5 Support Assistant are exported to the file system.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

README.md Outdated
}
```

Projects can also add report files by itself by setting or enhancing the global `window._$files` array in the executed source code on the following way:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Projects can also add report files by itself by setting or enhancing the global `window._$files` array in the executed source code on the following way:
Projects can also add report files by themselves by setting or enhancing the global `window._$files` array in the executed source code in the following way:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -267,6 +267,35 @@ module.exports = function(config) {
});
};`,

invalidFileExportReporterUsage: () => `error 21:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
invalidFileExportReporterUsage: () => `error 21:
invalidFileExportReporterUsage: () => `Error 21:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not take over this suggestion to be consistent to the existing error messages

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine, but could we have a central resources file (like i18n) where all error messages are stored and can be easily modified? Then we could easily fix such things without having to sacrifice consistency.

KlattG
KlattG previously approved these changes Nov 30, 2021
@@ -267,6 +267,35 @@ module.exports = function(config) {
});
};`,

invalidFileExportReporterUsage: () => `error 21:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine, but could we have a central resources file (like i18n) where all error messages are stored and can be easily modified? Then we could easily fix such things without having to sacrifice consistency.

if (config.fileExport) {
const testPageName = getTestPageName(qunitHtmlFile);
(testWindow.contentWindow._$files || []).forEach((file) => {
file.name = `TEST-${testPageName}-FILE-${file.name}`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this how it was done in Selenium? I.e. with the strings "TEST" and "FILE"?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this format is taken from the java implementation

}

const fileExtension = path.extname(fileName);
const fileNameWithoutExtension = fileName.slice(0, fileName.lastIndexOf(fileExtension));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternative:

Suggested change
const fileNameWithoutExtension = fileName.slice(0, fileName.lastIndexOf(fileExtension));
const fileNameWithoutExtension = path.basename(fileName, fileExtension);

See https://nodejs.org/api/path.html#pathbasenamepath-ext

But I wouldn't mind the current solution as well 🤷

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea but not an alternative because path.basename would trim the starting directory path

}

for (const file of result.exportFiles) {
const pathSegments = [outputDir, file.name];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const pathSegments = [outputDir, file.name];
const pathSegments = [outputDir, path.basename(file.name)];

"sanitize" file name to ensure it is really only a file name and not a path.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

for (const file of result.exportFiles) {
const pathSegments = [outputDir, file.name];
if (multiBrowsers) {
pathSegments.splice(1, 0, browser.name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pathSegments.splice(1, 0, browser.name);
pathSegments.splice(1, 0, path.basename(browser.name));

Same for browser name I guess

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

outputDir = defaultPath;
}

outputDir = helper.normalizeWinPath(path.resolve(config.basePath, outputDir));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, but I think normalization should happen before any platform specific path-action?

path.resolve won't actually resolve two Windows paths on a POSIX system, it will just append them. This might not be expected since on Windows the paths will actually be resolved in that case.

We need to normalize the configuration since it can be POSIX or Windows or both. Later when we path.join the file path, it will automatically be transformed into the right format for the current platform.

Maybe:

Suggested change
outputDir = helper.normalizeWinPath(path.resolve(config.basePath, outputDir));
outputDir = path.posix.resolve(helper.normalizeWinPath(config.basePath), helper.normalizeWinPath(outputDir));

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, a simple path.join should be sufficient since we already expect in browser.js the basePath to be in posix format.

@sap-sebelao
Copy link
Member Author

I looked at the changes and also retested this manually - everything seems to be still working as required for further processing of the files, the naming changes did not cause any unexpected trouble so far. Great job!

I will continue watching this and give feedback if required, but it seems like this is in good hands now. As the original committer I can't explicitly 'approve' this, so have at least a 👍 from me.

baseReporterDecorator(this);

async function writeSingleFile(outputFile, content) {
log.info(`Writing file: ${outputFile}`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't output the final path, as getUniqueFileName is called after.
Also, I think it would be sufficient to only have one "info" log per file, so this log should rather become "debug".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

return;
}

for (const file of result.exportFiles) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to add some error handling here?
Not only in case exportFiles is not an array, but also when name or content are undefined or define an unexpected type.
Currently, no name causes "undefined" to be used as name, and if content is not of type string, it causes an exception. I'd suggest to check for type string and log a warning if a file is not written.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might check out the Java implementation. Just search for LOGGER.severe("Invalid file object. \"name\" and \"content\" must be strings

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}

for (const file of result.exportFiles) {
const pathSegments = [outputDir, path.basename(file.name)];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Java we escaped the name to remove special characters and slashes:

result = result.replaceAll("[:*?\"<>|]", "");
result = result.replaceAll("[\\\\/]", ".");

Not sure whether we should just stick with that.

path.basename will still cause strange behavior when using ...
My question would be whether we want to make this "safe" so that it can't be misused or just that strange file names don't cause errors.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

for (const file of result.exportFiles) {
const pathSegments = [outputDir, path.basename(file.name)];
if (multiBrowsers) {
pathSegments.splice(1, 0, path.basename(browser.name));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, is covered now by escapeFileName

await writeSingleFile(exportPath, escapeFileName(file.name), file.content);
}
} catch (err) {
log.warn("An unexpected error occured while exporting files\n\t" + err.message);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we set exit code 1, we should also log this as an error

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

if (multiBrowsers) {
exportPath = path.join(exportPath, escapeFileName(browser.name));
}
try {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try-catch should be around the whole function body (onBrowserComplete). Otherwise errors won't be handled.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@larskissel larskissel requested a review from matz3 December 7, 2021 15:16
@RandomByte RandomByte dismissed their stale review December 7, 2021 15:52

My review has been addressed

Copy link
Member

@matz3 matz3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏻

@larskissel larskissel changed the title Add custom files read-save mechanism on complete [FEATURE] Add fileExport capability Dec 8, 2021
@larskissel larskissel merged commit 56aac75 into SAP:master Dec 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants