How to detect `eval` calls when addressing UI5 modules in runtime? - sapui5

As part of the preparation for the "Asynchronous Module Loading" enablement in FLP, one of its prerequisites is making sure that no eval call is triggered due to the HTML document being served with the response header Content-Security-Policy and its directive script-src omitting unsafe-eval.
Is there a feature in UI5 that logs all eval calls in runtime triggered by incorrectly addressed modules?

Resolution
Open the browser console (F12) and ensure that "Warnings" logs are visible.
Start the app with the UI5 config URL parameter sap-ui-xx-debugModuleLoading=true and make sure that the debug mode is not unnecessarily enabled.
In the browser console, filter by "(using eval)".
Example
Given
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/comp/library",
], function(Controller, sapUiCompLib) {
// ...
const ValueHelpRangeOperation = sapUiCompLib.valuehelpdialog.ValueHelpRangeOperation; // enum from module "sap/ui/comp/library"
const ValueHelpDialog = sapUiCompLib.valuehelpdialog.ValueHelpDialog; // control from module "sap/ui/comp/valuehelpdialog/ValueHelpDialog"
return Controller.extend("my.controller.MyController", {
onSomething: function () {
const vhDialog = new ValueHelpDialog(/*...*/);
// ...
},
// ...
});
});
Logs
Solution
Declare the missing dependency to "sap/ui/comp/valuehelpdialog/ValueHelpDialog".
No need to declare transitive dependencies that were also logged ( : ...).
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/comp/library",
"sap/ui/comp/valuehelpdialog/ValueHelpDialog" // <-- Declare the module dependency
], function(Controller, sapUiCompLib, ValueHelpDialog) {
// ...
const ValueHelpRangeOperation = sapUiCompLib.valuehelpdialog.ValueHelpRangeOperation; // enum from module "sap/ui/comp/library"
// const ValueHelpDialog = sapUiCompLib.valuehelpdialog.ValueHelpDialog; <-- Remove
return Controller.extend("my.controller.MyController", {
onSomething: function () {
const vhDialog = new ValueHelpDialog(/*...*/);
// ...
},
// ...
});
});
Module name to declare as dependency can be seen in the UI5 API reference:

Related

Mocking authentication when testing MSAL React Apps

Our app is wrapped in the MSAL Authentication Template from #azure/msal-react in a standard way - key code segments are summarized below.
We would like to test app's individual components using react testing library (or something similar). Of course, when a React component such as SampleComponentUnderTest is to be properly rendered by a test as is shown in the simple test below, it must be wrapped in an MSAL component as well.
Is there a proper way to mock the MSAL authentication process for such purposes? Anyway to wrap a component under test in MSAL and directly provide test user's credentials to this component under test? Any references to useful documentation, blog posts, video, etc. to point us in the right direction would be greatly appreciated.
A Simple test
test('first test', () => {
const { getByText } = render(<SampleComponentUnderTest />);
const someText = getByText('A line of text');
expect(someText).toBeInTheDocument();
});
Config
export const msalConfig: Configuration = {
auth: {
clientId: `${process.env.REACT_APP_CLIENT_ID}`,
authority: `https://login.microsoftonline.com/${process.env.REACT_APP_TENANT_ID}`,
redirectUri:
process.env.NODE_ENV === 'development'
? 'http://localhost:3000/'
: process.env.REACT_APP_DEPLOY_URL,
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: false,
},
system: {
loggerOptions: {
loggerCallback: (level, message, containsPii) => {
if (containsPii) {
return;
}
switch (level) {
case LogLevel.Error:
console.error(message);
return;
case LogLevel.Info:
console.info(message);
return;
case LogLevel.Verbose:
console.debug(message);
return;
case LogLevel.Warning:
console.warn(message);
return;
default:
console.error(message);
}
},
},
},
};
Main app component
const msalInstance = new PublicClientApplication(msalConfig);
<MsalProvider instance={msalInstance}>
{!isAuthenticated && <UnauthenticatedHomePage />}
{isAuthenticated && <Protected />}
</MsalProvider>
Unauthenticated component
const signInClickHandler = (instance: IPublicClientApplication) => {
instance.loginRedirect(loginRequest).catch((e) => {
console.log(e);
});
};
<UnauthenticatedTemplate>
<Button onClick={() => signInClickHandler(instance)}>Sign in</Button>
</UnauthenticatedTemplate>
Protected component
<MsalAuthenticationTemplate
interactionType={InteractionType.Redirect}
errorComponent={ErrorComponent}
loadingComponent={LoadingComponent}
>
<SampleComponentUnderTest />
</MsalAuthenticationTemplate>
I had the same issue as you regarding component's test under msal-react.
It took me a couple of days to figure out how to implement a correct auth mock.
That's why I've created a package you will find here, that encapsulates all the boilerplate code : https://github.com/Mimetis/msal-react-tester
Basically, you can do multiple scenaris (user is already logged, user is not logged, user must log in etc ...) in a couple of lines, without having to configure anything and of course without having to reach Azure AD in any cases:
describe('Home page', () => {
let msalTester: MsalReactTester;
beforeEach(() => {
// new instance of msal tester for each test
msalTester = new MsalReactTester();
// spy all required msal things
msalTester.spyMsal();
});
afterEach(() => {
msalTester.resetSpyMsal();
});
test('Home page render correctly when user is logged in', async () => {
msalTester.isLogged();
render(
<MsalProvider instance={msalTester.client}>
<MemoryRouter>
<Layout>
<HomePage />
</Layout>
</MemoryRouter>
</MsalProvider>,
);
await msalTester.waitForRedirect();
let allLoggedInButtons = await screen.findAllByRole('button', { name: `${msalTester.activeAccount.name}` });
expect(allLoggedInButtons).toHaveLength(2);
});
test('Home page render correctly when user logs in using redirect', async () => {
msalTester.isNotLogged();
render(
<MsalProvider instance={msalTester.client}>
<MemoryRouter>
<Layout>
<HomePage />
</Layout>
</MemoryRouter>
</MsalProvider>,
);
await msalTester.waitForRedirect();
let signin = screen.getByRole('button', { name: 'Sign In - Redirect' });
userEvent.click(signin);
await msalTester.waitForLogin();
let allLoggedInButtons = await screen.findAllByRole('button', { name: `${msalTester.activeAccount.name}` });
expect(allLoggedInButtons).toHaveLength(2);
});
I am also curious about this, but from a slightly different perspective. I am trying to avoid littering the code base with components directly from msal in case we want to swap out identity providers at some point. The primary way to do this is to use a hook as an abstraction layer such as exposing isAuthenticated through that hook rather than the msal component library itself.
The useAuth hook would use the MSAL package directly. For the wrapper component however, I think we have to just create a separate component that either returns the MsalProvider OR a mocked auth provider of your choice. Since MsalProvider uses useContext beneath the hood I don't think you need to wrap it in another context provider.
Hope these ideas help while you are thinking through ways to do this. Know this isn't a direct answer to your question.

Javascript in nuxt plugins folder - how to use in component?

I have a javascript variable (var testButton) in my Nuxt plugins folder. I then added the file to my nuxt.config.js plugins. In my component, I have a Buefy button, and I'm trying to call the script:
<b-button #click="testButton">Click Me</b-button>
...
<script>
export default {
mounted () {
this.$testButton()
}
}
</script>
I import the script in my script section and have tried computed and mounted lifecycles. Not sure what I'm doing wrong. Thank you
Check the following things, you must be missing one or more:
1. Your plugin should export a method. That method should receive an 'inject' function and use it to register your 'testButton' function.
So, in your ~/plugins/testButton.js
export default (context, inject) => {
inject('testButton', () => {
console.log('testButton works!')
})
}
2. You shuold register your plugin correctly in the nuxt.conf.js file
Do it like so:
plugins: [
{ src: '~/plugins/testButton.js' },
],
3. Call it as '$testButton()' (note that Nuxt will have added a dollar sign to your method's name).
Your '$testButton' method will now be available from anywhere in your nuxt app. You don't have to import it o create any computed property.
<b-button #click="$testButton">Click Me</b-button>
<script>
export default {
}
</script>

How to perform beforeTest and afterTest method using typescript (protractor+cucumber)

Framework used - Protractor
BDD - Cucumber
Language - Typescript
Now i have implemented the framework and a test scenario is also running fine with protractor.
But the problem i am facing is when i write another cucumber scenario my test fails saying 'A session is either terminated or not started'
The above failure is because when my first cucumber scenario starts the appium server starts with in my config and at the end i close the server/driver
Now i have written another test scenario, since cucumber is independent of each scenario , when the sec starts it does not do the config again. Now i need a beforeTest method to call.
So i am not sure how to implement that in typescript,as i am new to it.
Tried the same concept of java way but not working out. There where examples for javascript but still did not help me out.
Tried creating a new util folder and placing my beforeTest inside that but the function is not calling there
Tried to use beforeLaunch()with in my config file, but still does not work out
my config file: config.ts
export let config: Config = {
allScriptsTimeout: 40000,
getPageTimeout: 40000,
setDefaultTimeout: 60000,
defaultTimeoutInterval: 30000,
specs: [
// '../../utils/beforeEach.ts',
'../../features/*.feature',
],
onPrepare: () => {
Reporter.createDirectory(jsonReports);
tsNode.register({
project: './tsconfig.json'
});
},
multiCapabilities: [
androidPixel2XLCapability,
// iPhoneXCapability
],
framework: 'custom',
frameworkPath: require.resolve('protractor-cucumber-framework'),
cucumberOpts: {
compiler: "ts:ts-node/register",
glue: ["steps"],
format: [
"json:./reports/json/cucumber_report.json",
],
require: ['supports/timeout.js', '../../stepdefinitions/*.ts'],
tags: "#firstPurchasePopup",
},
seleniumAddress: serverAddress,
onComplete: () => {
Reporter.createHTMLReport();
},
// =====
// Hooks
// =====
beforeTest: function () {
},
beforeLaunch(){
console.log("Before");
seleniumAddress: 'http://localhost:4723/wd/hub';
},
afterLaunch() {
console.log("After");
},
};
my other beforeEach.ts:
This is not working but what i tired and was not working.
import {After, AfterAll, Before} from "cucumber";
const serverAddress = 'http://localhost:4723/wd/hub';
import {beforeEach, afterEach, describe} from "selenium-webdriver/testing";
beforeEach(function () {
console.log("Before");
});
// });
afterEach(function () {
console.log("Before");
});
// let beforeEach: () => void;
// beforeEach = () => {
// console.log("Before Test");
// // config.multiCapabilities;
// seleniumAddress: serverAddress;
// };
//
// let afterEach: () => void;
// afterEach = () => {
// console.log("After Test");
// };
This is my feature file: bonus.feature
this is my feature file:
Background:
Given I launch the app
Then I should see the popup window for the Bonus
And I verify the UI
Then I tap on ok button
And The popup window should not be seen
#firstPurchasePopup
Scenario: firstPurchasePopup new join button
When I tap on the 'New ' button
And The popup window should not be seen
Then I navigate back from join page to home page
Then The popup window should not be seen
Then I close the app
#firstPurchasePopup
Scenario: firstPurchasePopup login button
And I tap on log in button on the initial screen
Then I navigate back from login page to home page
And The popup window should not be seen
Then I close the app
I expect my the scenario what i have written to execute both one after the other , like execute Scenario: firstPurchasePopup new join button which it does . But when it launches the app again for the sec Scenario: firstPurchasePopup login button does not work as the driver is not started again, since it was closed in prev one.
to start it i need to create beforeTest which i am facing difficutly to write the code
I haven't used Protractor with Cucumber, but I have used Cucumber & Typescript together. I resolved the problem by having a file cucumber.js in a root that is being loaded at the very beginning by default and looks like that:
var settings = "features/**/*.feature -r step-definitions/**/*.ts -r hooks/**/*.ts -r support/**/*.ts "
module.exports = {
"default": settings
}
However, I think in your case the solution would be adding a path to hooks file to config.cucumberOpts.require list instead to config.specs one.
Did you try it?
#All
Thanks for your inputs #mhyphenated
I figured out that the rather than using inside the config, i tried using the before and after in the hooks.ts ,also other than calling the server i was not actually calling the android driver, as below and that worked
beforeTest: function () {
beforeTest: function () {
},
beforeLaunch(){
console.log("Before");
seleniumAddress: 'http://localhost:4723/wd/hub';
},
hooks.ts
import { AndroidDriver } from "appium/node_modules/appium-android-driver";
let driver:AndroidDriver, defaultCaps;
driver = new AndroidDriver();
Before(function () {
// This hook will be executed before all scenarios
browser.ignoreSynchronization = false;
browser.manage().timeouts().implicitlyWait(500);
let defaultCaps = config.multiCapabilities[0];
console.log("defaultCaps = ", defaultCaps );
driver.createSession(defaultCaps);
driver.defaultWebviewName();
});

how to use third party javascript code in magento2 payment?

I am facing problem while adding third party javascript code in my payment module in magento2.
following is my code.
define(
[
'Magento_Payment/js/view/payment/cc-form',
'jquery',
'Vendorname_Modulename/js/stsdk'
'Magento_Payment/js/model/credit-card-validation/validator'
],
function (Component, $, STDirect) {
'use strict';
return Component.extend({
defaults: {
template: 'Vendorname_Modulename/payment/module-form'
},
getCode: function() {
return 'vendor_module';
},
isActive: function() {
return true;
},
validate: function() {
STDirect.setupSDK('23842', "testnumber", 'typeofenv');
STDirect.card.createToken(number, exp_month, exp_year, ccv, function (result) {
var secretkey = '';
if(result.status==0){
secretkey = result.card.secretkey;
}
document.write(JSON.stringify(result));
alert(secretkey);
});
var $form = $('#' + this.getCode() + '-form');
return $form.validation() && $form.validation('isValid');
}
});
}
);
I have tried above code, stsdk.js is loaded in network but it gives me following error :
ReferenceError: STDirect is not defined
STDirect.setupSDK('23842', "testnumber", 'sandbox');
I have also checked by load this js file in header but same error appear.
My question is how to execute third party javascript code in define scope.
I tried with the custom javascript function after define function but it is also not callable from validate function and when I use require[] function within define function it raise error.
I appreciate any help.

Durandal, Socket.io and require

I'm having a hard time setting up Durandal to include the socket io library.
I've tried a few methods, including the path in the main.js library but as it isn't a single js file, it has never worked.
If anyone has experience with this, I'd extremely appreciate it!!
Thanks
Edited with code,
requirejs.config({
paths: {
'text': '../lib/require/text',
'durandal':'../lib/durandal/js',
'plugins' : '../lib/durandal/js/plugins',
'transitions' : '../lib/durandal/js/transitions',
'knockout': '../lib/knockout/knockout-3.1.0',
'bootstrap': '../lib/bootstrap/js/bootstrap',
'jquery': '../lib/jquery/jquery-1.9.1',
'toastr' : '../lib/toastr/toastr',
'moment' : '../lib/moment/moment',
'when' : '../lib/when/when',
'flipclock': '../lib/flipclock/flipclock',
'require': '../lib/require/require'
},
shim: {
'bootstrap': {
deps: ['jquery'],
exports: 'jQuery'
}
}
});
define(['durandal/system', 'durandal/app', 'durandal/viewLocator', 'require', 'plugins/http'], function (system, app, viewLocator, require, http) {
var io = require('socket.io')(http);
In order to work you need to add socket.io to the paths config, as well as define a shim.
Make sure the path to socket io is setup properly.
paths: {
....
'socketio': 'PATH_TO/socket.io/socket.io'
},
shim: {
'socketio': {
'exports': 'io'
}
}
define(['durandal/system', 'durandal/app', 'durandal/viewLocator', 'bootstrap',
'socketio', 'knockout'],
function (system, app, viewLocator, bootstrap, io, ko) {
// if its on the same host
var testsocket = io.connect(window.location.hostname);
// otherwhise
var testsocket = io.connect(PATHTOSOCKET);
});
that should do the trick
EDIT:
Additionally it seems like you want to use the NPM package in the frontend, which is clearly not the way to go. Socket.IO creates a frontend proxy, which can be utilized the way described above.
You need to include socket.io in your requirejs configuration:
requirejs.config({
paths: {
...,
'socket': 'path/to/socket.io'
},
...
});
Then, you can access the library from within your application like such:
define([..., 'socket'],
function (..., socket) {
// body here with access to socket
socket.doSomething();
});
paths: {
'text': '../lib/require/text',
'durandal':'../lib/durandal/js',
'plugins' : '../lib/durandal/js/plugins',
'transitions' : '../lib/durandal/js/transitions',
'knockout': '../lib/knockout/knockout-3.1.0',
'bootstrap': '../lib/bootstrap/js/bootstrap',
'jquery': '../lib/jquery/jquery-1.9.1',
'toastr' : '../lib/toastr/toastr',
'moment' : '../lib/moment/moment',
'when' : '../lib/when/when',
'flipclock': '../lib/flipclock/flipclock',
'require': '../lib/require/require',
'socket': '../lib/socket.io/lib/socket'
},
So I've included it in my requirejs configuration.
define(['durandal/system', 'durandal/app', 'durandal/viewLocator', 'require', 'plugins/http', 'socket'], function (system, app, viewLocator, require, http, socket) {
This seems to have help but now I'm getting,
Module name "events" has not been loaded yet for context: _. Use require([]) exception
. The page does load now, but I assume I must include "events" too?
The issues seems to be the standard require for socket io is something like this,
var io = require('socket.io')(http);
Which must resolve all the dependencies as the npm socket.io has modules within it. The requirejs path similar loads a single js file, were socket.io has many.