Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,11 +362,11 @@ void Promise.all([import("unit/controller/App.qunit")]).then(() => {
will be converted to:

```js
"sap.ui.require([], function () {
"use strict";
"use strict";

QUnit.config.autostart = false;
"sap.ui.require([], function () {
function __ui5_require_async(path) { /* ... */ }
QUnit.config.autostart = false;
void Promise.all([__ui5_require_async("unit/controller/App.qunit")]).then(() => {
QUnit.start();
});
Expand All @@ -375,6 +375,8 @@ will be converted to:

> :warning: Although `sap.ui.define` and `sap.ui.require` may appear similar from an API perspective, they have different behaviors. To understand these differences, please read the section titled "Using sap.ui.require instead of sap.ui.define on the top level" in the [Troubleshooting for Loading Modules](https://ui5.sap.com/#/topic/4363b3fe3561414ca1b030afc8cd30ce).

> :bulb: The plugin detects the global usage of `QUnit.config.autostart` and moves this out of the `sap.ui.require` or `sap.ui.define` block automatically to ensure that the config is applied sychronously when loading the module. The move can be supressed with the configuration option `noWrapQUnitConfigAutostart`. If `QUnit` is imported, e.g. `import QUnit from "qunit";` then this is detected and the autostart config is not moved as it must apply locally.

### Converting ES classes into Control.extend(..) syntax

By default, the plugin converts ES classes to `Control.extend(..)` syntax if the class extends from a class which has been imported.
Expand Down Expand Up @@ -795,6 +797,7 @@ In general, comments are preserved, but for each class property/method whose pos
### Wrapping

- `noWrapBeforeImport` (Default: false) Does not wrap code before the first import (if there are imports).
- `noWrapQUnitConfigAutostart` (Default: true) Does not wrap the `QUnit.config.autostart` in the `sap.ui.require` or `sap.ui.define` block.

### Class Conversion

Expand Down
40 changes: 36 additions & 4 deletions packages/plugin/__test__/__snapshots__/test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1647,9 +1647,40 @@ exports[`sap-ui-require othermodule-noannotation.js 1`] = `
`;

exports[`sap-ui-require testsuite-annotation.qunit.js 1`] = `
"sap.ui.require([], function () {
""use strict";

QUnit.config.autostart = false;
sap.ui.require([], function () {
function __ui5_require_async(path) {
return new Promise(function (resolve, reject) {
sap.ui.require([path], function (module) {
if (!(module && module.__esModule)) {
module = module === null || !(typeof module === "object" && path.endsWith("/library")) ? {
default: module
} : module;
Object.defineProperty(module, "__esModule", {
value: true
});
}
resolve(module);
}, function (err) {
reject(err);
});
});
}
void Promise.all([__ui5_require_async("unit/controller/App.qunit")]).then(() => {
QUnit.start();
});
});"
`;

exports[`sap-ui-require testsuite-annotation-with-qunit-import.qunit.js 1`] = `
"sap.ui.require(["qunit"], function (__QUnit) {
"use strict";

function _interopRequireDefault(obj) {
return obj && obj.__esModule && typeof obj.default !== "undefined" ? obj.default : obj;
}
function __ui5_require_async(path) {
return new Promise(function (resolve, reject) {
sap.ui.require([path], function (module) {
Expand All @@ -1667,6 +1698,7 @@ exports[`sap-ui-require testsuite-annotation.qunit.js 1`] = `
});
});
}
const QUnit = _interopRequireDefault(__QUnit);
QUnit.config.autostart = false;
void Promise.all([__ui5_require_async("unit/controller/App.qunit")]).then(() => {
QUnit.start();
Expand All @@ -1675,9 +1707,10 @@ exports[`sap-ui-require testsuite-annotation.qunit.js 1`] = `
`;

exports[`sap-ui-require testsuite-noannotation.qunit.js 1`] = `
"sap.ui.define([], function () {
"use strict";
""use strict";

QUnit.config.autostart = false;
sap.ui.define([], function () {
function __ui5_require_async(path) {
return new Promise(function (resolve, reject) {
sap.ui.require([path], function (module) {
Expand All @@ -1695,7 +1728,6 @@ exports[`sap-ui-require testsuite-noannotation.qunit.js 1`] = `
});
});
}
QUnit.config.autostart = false;
void Promise.all([__ui5_require_async("unit/controller/App.qunit")]).then(() => {
QUnit.start();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* @sapUiRequire */
import QUnit from "qunit";

// https://api.qunitjs.com/config/autostart/
QUnit.config.autostart = false;

// import all your QUnit tests here
void Promise.all([import("unit/controller/App.qunit")]).then(() => {
QUnit.start();
});
47 changes: 46 additions & 1 deletion packages/plugin/src/modules/helpers/wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export function wrap(visitor, programNode, opts) {
}
}

let moveUseStrictIfNeeded = false;
const preDefine = [...ignoredImports];
// If the noWrapBeforeImport opt is set, split any code before the first import and afterwards into separate arrays.
// This should be done before any interops or other vars are injected.
Expand All @@ -101,6 +102,25 @@ export function wrap(visitor, programNode, opts) {
reachedFirstImport = true;
}
}
moveUseStrictIfNeeded = true;
body = newBody;
}

// If the QUnit.config.autostart is found it needs to be moved to the top of the program
if (
opts.noWrapQUnitConfigAutostart === undefined ||
opts.noWrapQUnitConfigAutostart
) {
const qunitConfigAutostart = findQUnitConfigAutostart(body, imports);
if (qunitConfigAutostart) {
preDefine.push(qunitConfigAutostart);
body = body.filter((node) => node !== qunitConfigAutostart);
moveUseStrictIfNeeded = true;
}
}

// if code has been moved to preDefine, we need to move the "use strict" directive
if (moveUseStrictIfNeeded) {
if (
!opts.neverUseStrict &&
preDefine.length &&
Expand All @@ -111,7 +131,6 @@ export function wrap(visitor, programNode, opts) {
...(programNode.directives || []),
];
}
body = newBody;
}

if (injectDynamicImportHelper) {
Expand Down Expand Up @@ -220,6 +239,32 @@ function hasUseSapUiRequire(comments, body, remove) {
});
}

function findQUnitConfigAutostart(body, imports) {
// if one imports QUnit, we don't need to move the QUnit.config.autostart
// as the configuration should apply to the local QUnit module
if (imports?.some((imp) => imp.name === "QUnit")) {
return undefined;
}
// find the QUnit.config.autostart
return body?.find((node) => {
return (
t.isExpressionStatement(node) &&
t.isAssignmentExpression(node.expression) &&
t.isMemberExpression(node.expression.left) &&
t.isMemberExpression(node.expression.left.object) &&
t.isIdentifier(node.expression.left.object.object) &&
node.expression.left.object.object.name === "QUnit" &&
t.isIdentifier(node.expression.left.object.property) &&
node.expression.left.object.property.name === "config" &&
t.isIdentifier(node.expression.left.property) &&
node.expression.left.property.name === "autostart" &&
node.expression.operator === "=" /* &&
t.isBooleanLiteral(node.expression.right) &&
node.expression.right.value === false */
);
});
}

function generateDefineOrRequire(body, imports, exportGlobal, useRequire) {
const defineOpts = {
SOURCES: t.arrayExpression(imports.map((i) => t.stringLiteral(i.src))),
Expand Down