CASL is not working properly in Vue Production Mode - vue.js

I have defined some rules for specific roles, they all are working fine. But when I build vue project in production mode, all the rules gives false. Details are here below:
I have this file ability.js, which is giving me rules:
export const getRules = (role, userId) => {
const { can, cannot, rules } = AbilityBuilder.extract()
switch(role) {
case 'TENANT_ADMIN':
can('manage', 'all')
break
case 'TENANT_AGENT':
can('view', 'ConversationView')
break
case 'TENANT_AGENT_LIMITED':
can('view', 'ConversationView', { userId: userId })
break
}
return rules
}
I'm updating rules like this in App.vue (all values are valid)
this.$ability.update(getRules(role, userId))
I'm checking permissions using below code.
class ConversationView {
constructor(props) {
Object.assign(this, props)
}
}
this.$can('view', new ConversationView({ userId: Id }))
Now, when I run this code in local/development mode. It is working fine (giving me true where it needs to), but when I generate a production build it is not working as expected (always gives me false)
Development Build Command:
vue-cli-service build --mode local --modern
Development Build .env.local
VUE_APP_STAGE=development
NODE_ENV=development
Production Build Command:
vue-cli-service build --mode prod --modern
Production Build .env.prod
VUE_APP_STAGE=production
NODE_ENV=production
Let me know why this is happening.
Replicated the steps here.
Follow below link to view running and expected version:
LINK 01
Output:
Checking for '1' => true
Checking for 1 => false
Checking for '2' => false
Clone the same project in your local, or download it from [github 2
After running, we're getting this output:
Checking for '1' => false
Checking for 1 => false
Checking for '2' => false

Got the solution. Because of minification for production build code was not working as expected. Had to define modelName function to return proper name.
Follow the link for more info.
https://stalniy.github.io/casl/abilities/2017/07/21/check-abilities.html#instance-checks

Related

Get zero coverage with nyc and playwright

I'm struggling to set up coverage correctly using Playwright. It reports 0 coverage in all files (except the test files themselves, if I include them).
I'm getting inspiration from https://playwright.dev/docs/api/class-coverage and https://github.com/bgotink/playwright-coverage/blob/main/src/fixtures.ts. Our project is a monorepo where tests in a folder e2e-tests/ run end to end tests on servers contained in other adjacent folders, e.g. frontend/.
The current setup is using a page fixture like so in each test-file:
// frontend.spec.ts
import { test, expect } from "../fixtures";
test("something", ({ page ) => {
// Do test stuff with page
});
where the fixture is defined as
// fixtures/page.ts
import { Page, TestInfo } from "#playwright/test";
const pageWithCoverage = async (
{ page, browserName }: { page: Page; browserName: string },
use: (page: Page) => Promise<void>,
testInfo: TestInfo
) => {
if (!page.coverage) throw new Error(`Could not collect coverage with browser "${browserName}"`);
console.log("📈 Collecting coverage");
await page.coverage.startJSCoverage();
await use(page);
await page.coverage.stopJSCoverage();
};
export default pageWithCoverage;
To collect coverage I run
npx nyc --all --cwd ".." --include "**/frontend/**/* --nycrc-path e2e-tests/.nycrc npm t
where the relevant part concerning the file structure is:
--all --cwd ".." --include "**/frontend/**/*"
I'm using a .nycrc file containing nyc-config-tsx in order to instrument tsx files:
// .nycrc
{
"extends": "nyc-config-tsx",
"all": true
}
Can you tell what the issue is?
The frontend is built using next.
I get similar results storing results to files using v8toIstanbul and running npx nyc report

VueJS - prod build removes attribute quotes from HTML

First, is it standard to remove attribute quotes from HTML in a minified production build? It seems like that would cause problems in some browsers / platforms? If so, then everything below doesn't really matter, but I'm still curious.
I have the below in my vue.config.js and it works to keep attribute quotes in the prod build, but breaks yarn serve.
Local Vue version 2.6.12. #vue/cli version 4.5.4.
chainWebpack: (config) => { // chainWebpack grayed out
config.plugin("html").tap((args) => {
args[0].minify.removeAttributeQuotes = false;
return args;
});
},
It doesn't seem to find minify - I keep getting: ERROR TypeError: Cannot set property 'removeAttributeQuotes' of undefined
First, is it standard to remove attribute quotes from HTML in a minified production build?
It's not standard but still valid HTML. The attribute quotes are removed in production builds to reduce the output size of the HTML size so if you're en DEV environment (like when you're running yarn serve) the object args[0].minify is undefined.
So for keeping the quotes in production build and not get errors in other environments, you can set the attribute removeAttributeQuotes as follows (instead of modifying its value, like in your code):
chainWebpack: (config) => {
config.plugin('html').tap((args) => {
args[0].minify = {
...args[0].minify,
removeAttributeQuotes: false,
}
return args
})
},
See related issue

Change properties in manifest.json file on build

I have a website with 2 domains like Page1.com and Page2.com. In my manifest.json file i have set the name to Page 1, but when the website is build and published to Page1.com and to Page2.com i want to change the name to be the same as the domain name. But how can i do this in my build step? Today i se Page 1 when i visit Page2.com.
I have tried to change the meta, application-name in my code to get the correct name, but this don't work.
My vue.config
const manifestJSON = require('./public/manifest.json')
module.exports = {
pluginOptions: {
i18n: {
locale: 'en',
fallbackLocale: 'en',
localeDir: 'locales',
enableInSFC: true
}
},
runtimeCompiler: true,
pwa: {
themeColor: manifestJSON.theme_color,
name: manifestJSON.short_name,
msTileColor: manifestJSON.background_color,
appleMobileWebAppCapable: 'yes',
appleMobileWebAppStatusBarStyle: 'black',
workboxPluginMode: 'InjectManifest',
workboxOptions: {
swSrc: 'service-worker.js',
exclude: [
/_redirects$/
]
}
}
}
This site is build with VueJs and use Netlify as host.
So the manifest file is generated by vue-cli every time you build your app. So you shouldn't be using it to seed the vue-config file.
The one file that you could use the way you have shown here would be your package.json file - but it won't hold the values you are looking for.
Your Vue.config file is where you would enter, manually, the pwa info like theme and background color, etc.
To get back to your initial question, you could create two separate build scripts in your package.json, one for page1 and one for page2, and use environment variables to specify the name you ant to use:
"scripts": {
"page1": "env SITE_NAME='Page 1' npm run prod",
"page2": "env SITE_NAME='Page 2' npm run prod",
...
}
Then in your vue.config file, you can use the variable to build your pwa object:
pwa: {
name: process.env.SITE_NAME,
...
}
Finally, you can build your apps by calling
npm run page1
Be careful though: every build will overwrite your public folder! Depending on your context, how/when you build each app, you may have to take additional steps to generate two separate output folders.
The easiest way is to use process.argv to get a command line argument.
For example if you command to run the file is:
node file.js
Then using:
node file.js env_variable_str
Will have process.argv[process.argv.length - 1] === "env_variable_str"
In my case the manifest had to change not just the value but also add/remove a key depending on the argument. So I made a template (manifest_template.json) and used a "build helper" to create the correct manifest based on my argument in the public/ folder. Then I chained this command with npm run build and had another chaining command which made the zip folder.
My workflow: create manifest.json in public -> npm run build -> make zip with correct name
Let me know if you want to see the code!

Error running tests with Detox in Expo React Native project

When I try to run my tests using detox in a React Native Expo project, I get the following error:
detox[18834] WARN: [Client.js/PENDING_REQUESTS] App has not responded to the network requests below:
(id = -1000) isReady: {}
That might be the reason why the test "Login workflow should have login screen" has timed out.
detox[18834] INFO: Login workflow: should have login screen [FAIL]
FAIL e2e/firstTest.e2e.js (137.697 s)
Login workflow
✕ should have login screen (120015 ms)
● Login workflow › should have login screen
thrown: "Exceeded timeout of 120000 ms for a hook.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
7 | });
8 |
> 9 | it('should have login screen', async () => {
| ^
10 | await expect(element(by.id('loginFormTitle'))).toBeVisible()
11 | });
12 |
at firstTest.e2e.js:9:3
at Object.<anonymous> (firstTest.e2e.js:8:1)
detox[18833] ERROR: [cli.js] Error: Command failed: node_modules/.bin/jest --config e2e/config.json '--testNamePattern=^((?!:android:).)*$' --maxWorkers 1 e2e
I am running iPhone 11 Pro simulator, and the expo app is already running in a separate server. I also have a Exponent.app in my /bin folder, which I downloaded from Expo's website. The logic in my test case doesn't require any timeout and it involves just a simple login screen.
Any solution for this error?
I had a similar issue using the latest version of Expo (v39).
It seems like the issue is that Detox waits for an app is ready event before running the tests, but this doesn’t get triggered with the most recent versions of the Expo SDK.
The solution I ended up with was to create a standalone build of the app and run Detox against that.
My .detoxrc.json looks like:
{
...,
"configurations": {
"ios": {
"type": "ios.simulator",
"build": "expo build:ios -t simulator",
"binaryPath": "bin/myapp.app",
}
}
}
As of December 2020, I'm using detox 17.14.3 with Expo 39.0.5 and I've managed to solve this issue without needing to use a standalone build. Patch and explanation provided below.
It turns out that detox-expo-helpers is overriding an environment variable (specifically SIMCTL_CHILD_DYLD_INSERT_LIBRARIES) to specify the path to the ExpoDetoxHook framework (provided by the expo-detox-hook package). Well, that update to the environment now happens too late in the cycle. It takes place when running Detox's reloadApp, but by then, Detox has started up Jest which has workers running with their own copy of process.env. Workers get a copy of process.env at the time of creation, and they are not shared with the parent process, so the changes this library makes to environment variables are not reflected inside Jest workers. The hook framework is not available to the running application, and so the Detox is stuck waiting for a ready signal that doesn't come.
Detox's launchApp for iOS simulator uses SIMCTL_CHILD_DYLD_INSERT_LIBRARIES to specify it's own library, but because the environment vars are isolated in the worker, it does not see the change this package makes. To solve this, I modified this library to expose the changes to process.env as a separate exported function, and then I call that much earlier in the test lifecycle to ensure it is set before any workers are started. Here is a patch compatible with patch-package.
# file patches/detox-expo-helpers+0.6.0.patch
diff --git a/node_modules/detox-expo-helpers/index.js b/node_modules/detox-expo-helpers/index.js
index 864493b..3147a55 100644
--- a/node_modules/detox-expo-helpers/index.js
+++ b/node_modules/detox-expo-helpers/index.js
## -45,7 +45,16 ## function resetEnvDyldVar(oldEnvVar) {
}
}
-const reloadApp = async (params) => {
+let initialized = false;
+let detoxVersion;
+let oldEnvVar;
+const init = () => {
+ if (initialized) {
+ return;
+ }
+
+ initialized = true;
+
if (!fs.existsSync(expoDetoxHookPackageJsonPath)) {
throw new Error("expo-detox-hook is not installed in this directory. You should declare it in package.json and run `npm install`");
}
## -56,12 +65,16 ## const reloadApp = async (params) => {
throw new Error ("expo-detox-hook is not installed in your osx Library. Run `npm install -g expo-detox-cli && expotox clean-framework-cache && expotox build-framework-cache` to fix this.");
}
- const detoxVersion = getDetoxVersion();
- const oldEnvVar = process.env.SIMCTL_CHILD_DYLD_INSERT_LIBRARIES;
+ detoxVersion = getDetoxVersion();
+ oldEnvVar = process.env.SIMCTL_CHILD_DYLD_INSERT_LIBRARIES;
if (semver.gte(detoxVersion, '9.0.6')) {
process.env.SIMCTL_CHILD_DYLD_INSERT_LIBRARIES = expoDetoxHookFrameworkPath;
}
+}
+
+const reloadApp = async (params) => {
+ init();
const formattedBlacklistArg = await blacklistCmdlineFormat(params && params.urlBlacklist);
const url = await getAppUrl();
## -121,5 +134,6 ## module.exports = {
getAppUrl,
getAppHttpUrl,
blacklistLiveReloadUrl,
+ init,
reloadApp,
};
With that in place, I modified my e2e/environment.js file to look like the following. The addition is the initExpo call. When it runs this early in the test lifecycle, the environment is modified before any workers are started, and as a result, calls to reloadApp no longer wait indefinitely.
/* eslint-disable import/no-extraneous-dependencies */
const { init: initExpo } = require('detox-expo-helpers');
const { DetoxCircusEnvironment, SpecReporter, WorkerAssignReporter } = require('detox/runners/jest-circus');
class CustomDetoxEnvironment extends DetoxCircusEnvironment {
constructor(config) {
super(config);
initExpo();
// Can be safely removed, if you are content with the default value (=300000ms)
this.initTimeout = 300000;
// This takes care of generating status logs on a per-spec basis. By default, Jest only reports at file-level.
// This is strictly optional.
this.registerListeners({
SpecReporter,
WorkerAssignReporter,
});
}
}
module.exports = CustomDetoxEnvironment;

How do you remove console.log from a build using the JS Quasar Framework?

I am trying the Quasar Framework (for those not familiar, it's based on Vue) and it's going well. However I've tried running a build (npm run build) and get repeated:
error Unexpected console statement no-console
... so the build fails because it sees console.log(...) and is not happy. My options:
don't use console.log in development. But it's handy.
comment out the eslint rule that presumably enforces that, so letting console.log into production. But that's not ideal for performance/security.
have the build automatically remove any console.log. That's what I'm after.
But how?
I took a look at the build https://quasar.dev/quasar-cli/cli-documentation/build-commands and it mentions using webpack internally and UglifyJS too. Given that, I found this answer for removing console.log in a general Vue/webpack project: https://github.com/vuejs-templates/webpack-simple/issues/21
... but if that's how, where does that go within Quasar since there is no webpack config file? I imagine in the quasar.conf.js file (since I see an 'extendWebpack' line in there - sounds promising). Or is there a better way to do it? How do other people remove console.log in production when using Quasar? Or handle logging without it?
Thanks!
https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-build
quasar.conf.js:
module.exports = function (ctx) {
return {
...
build: {
...
uglifyOptions: {
compress: { drop_console: true }
}
},
}
}
The above will result in configuring terser plugin with the following:
terserOptions: {
compress: {
...
drop_console: true
},
(https://github.com/terser/terser#compress-options)
(you can see the generated config with quasar inspect -c build -p optimization.minimizer)
You still also need to remove the eslint rule to avoid build errors, see https://github.com/quasarframework/quasar/issues/5529
Note:
If you want instead to configure webpack directly use:
quasar.conf.js:
module.exports = function (ctx) {
return {
...
build: {
...
chainWebpack (chain) {
chain.optimization.minimizer('js').tap(args => {
args[0].terserOptions.compress.drop_console = true
return args
})
}
},
}
}
It will do the same as above.
See https://quasar.dev/quasar-cli/cli-documentation/handling-webpack
and https://github.com/neutrinojs/webpack-chain#config-optimization-minimizers-modify-arguments
https://github.com/quasarframework/quasar/blob/dev/app/lib/webpack/create-chain.js#L315
1 Edit package.json in Vue's project what had created it before.
2 Then find "rules": {}.
3 Change to this "rules":{"no-console":0}.
4 if you Vue server in on, off it and run it again. Then the issue will be done.
As an alternative I can suggest using something like loglevel instead of console.log. It's quite handy and allows you to control the output.