#casl/vue: What should by ability.js file look like? - vue.js

I'm trying to integrate #casl/vue with Vue 3, and I'm afraid I'm having problems.
Per the instructions, I've added the following to my /main.js:
import { abilitiesPlugin } from '#casl/vue';
import ability from './services/ability';
app.use(abilitiesPlugin, ability, {
useGlobalProperties: true
})
So far, so good. However, it's unclear what I should put in /services/ability.js.
I tried the following (based on this), and it works:
import { defineAbility } from '#casl/ability';
export default defineAbility((can, cannot) => {
can('manage', 'all');
cannot('delete', 'User');
});
But, of course, this doesn't allow me to use different permissions for different users.
So I tried the following instead (based on this):
import { defineAbility } from '#casl/ability';
export default (user) => defineAbility((can) => {
can('read', 'Article');
if (user.isLoggedIn) {
can('update', 'Article', { authorId: user.id });
can('create', 'Comment');
can('update', 'Comment', { authorId: user.id });
}
});
...and that doesn't work. In the console, I see:
plugin.ts:12 Uncaught Error: Please provide an Ability instance to abilitiesPlugin plugin
at l (plugin.ts:12:11)
at Object.use (runtime-core.esm-bundler.js:3812:21)
at main.js?t=1651580949947:29:5
Got any hints? I'm finding the documentation to be pretty unclear. A practical example would really help me!
Thanks!

It means you must pass plugins as an instance of Ability
const ability = new Ability()
.use(abilitiesPlugin, ability, {
....
})

Related

Nuxt Generate dynamic routes from the store

I'm using nuxt.js and now need to generate my dynamic pages by running npm run generate. However my list items needed to make dynamic items are stored in the store, so I need to map over them somehow so the generate can make the routes for them
How can I access the store in my nuxt.config.js?
generate: {
dir: 'wwwroot', //override the default generation dir to create everything straight in wwwroot
routes() {
let vdc = this.$store.vdcServers.map(server => `/virtual-data-centres/${server.slug}`);
return Promise.all([vdc]).then(values => {
return values.join().split(',');
})
}
}
Output
ERROR Could not resolve routes
FATAL Cannot read properties of undefined (reading '$store')
To my knowledge, you cannot access the store from that place. Maybe with some hooks? I doubt.
Meanwhile, if you have your elements available in your store you should be able to find them back by making a quick axios call or like I think.
This kind of approach is totally fine
import axios from 'axios'
export default {
generate: {
routes(callback) {
axios
.get('https://my-api/users')
.then(res => {
const routes = res.data.map(user => {
return '/users/' + user.id
})
callback(null, routes)
})
.catch(callback)
}
}
}
It may be a bit of code duplication, meanwhile, it's still the simplest way to go.
Otherwise, you could try to persist it to some localStorage or any similar solution, to have it both in Vuex and during your generation.

I'm switching from Vuex to Pinia in Vue 3 and my unit tests are now failing. I can't seem to be able to create custom mock actions

Here's a simple example on the forgot password reset page of my app, I would want to bypass the server side and just have the password reset to succeed on click so I would write a test and use the custom test store like so:
const customStore = {
state() {
return {
Authentication: {
passwordResetSuccess: false,
},
};
},
mutations: {
SET_RESET_PASSWORD_SUCCESS(state) {
state.Authentication.passwordResetSuccess = true;
},
},
actions: {
forgotPasswordResetPassword() {
this.commit('SET_RESET_PASSWORD_SUCCESS');
},
},
};
Then I could include the custom store in my beforeEach() and it worked great. I've tried everything I can think of to get this to work with pinia, but it doesn't seem to work.
I'm using jest along with vue/test-utils.
I basically tried just creating the test pinia store, but I can't figure out how to get the component to use the custom test store.
const useCustomStore = defineStore('AuthenticationStore', {
state: () => ({
passwordResetSuccess: false,
}),
actions: {
forgotPasswordResetPassword() {
this.passwordResetSuccess = true;
},
},
});
const authenticationStore = useCustomStore();
I can't directly add it as a plugin because it can't find an active instance of pinia.
I went through this guide: https://pinia.vuejs.org/cookbook/testing.html#unit-testing-a-store
and I also tried using jest mock as described here: https://stackoverflow.com/a/71407557/4697639
But it still failed.
If anyone has any idea how to create a custom store that can be used by the component and actually hits the custom actions, I could really use some help figuring this out. Thank you!!
Tao mentioned in the comments that this isn't a good way to do unit tests. I will mark this as resolved and fix how I do the testing.

Page reload causes Vuex getter to return undefined

Using Vue.js (Vuetify for FE).
A page reload causes the getter in Vuex to fail with pulling required data from the store. The getter returns undefined. The code can be found on GitHub at: https://github.com/tineich/timmyskittys/tree/master/src
Please see the full details on this issue at timmyskittys.netlify.com/stage1. This page has complete info on the issue and instructions on how to view the issue.
Note, there is mention of www.timmyskittys.com in the issue description. This is the main site. timmyskittys.netlify.com is my test site. So, they are the same for all intents and purposes. But, my demo of this issue is at the Netlify site.
I read the complete issue in the website you mentioned. It's a generic case.
Say, for cat details page url: www.timmyskittys.com/stage2/:id.
Now in Per-Route Guard beforeEnter() you can set the cat-id in store. Then from your component call the api using the cat-id (read from getters)
I found the solution to my issue:
I had to move the call of the action which calls the mutation that loads the .json file (dbdata.json) into a computed() within App.vue. This was originally done in Stage1.vue.
Thanks all for responding.
I had the same issue and my "fix" if it can be called that was to make a timer, so to give the store time to get things right, like so:
<v-treeview
:items="items"
:load-children="setChildren"
/>
</template>
<script>
import { mapGetters } from 'vuex'
const pause = ms => new Promise(resolve => setTimeout(resolve, ms))
export default {
data () {
return {
children: []
}
},
computed: {
...mapGetters('app', ['services']),
items () {
return [{
id: 0,
name: 'Services',
children: this.children
}]
}
},
methods: {
async setChildren () {
await pause(1000)
this.children.push(...this.services)
}
}
}
</script>
Even though this is far from ideal, it works.

Need advice about testing using Chimp.js/Mocha in Meteor.js

I'm trying to teach myself testing with Meteor but there is so much conflicting and outdated info online it's really difficult to work out what I need to do.
My current situation it that I have an application using the latest Meteor version (and the imports folder structure).
I've installed chimp globally and have created a /tests directory.
My first test is using chimp/mocha to fill in a form and try to insert something to the database. I'm also using the xolvio/backdoor package and running chimp like so
chimp --ddp=http://localhost:3000 --mocha --path=tests
Here's my test code:
describe('Chimp Mocha', function() {
describe( 'Create a Client', function() {
it( 'should fill in add client form', function() {
browser.setValue('#clientName', 'Test')
.setValue('#clientEmail', 'test#test.com')
.selectByValue('#numberTeamMembers', '25')
.submitForm('#createClient')
});
it( 'should check the collections for new client data', function() {
let getClient = server.execute( function() {
return Clients.findOne({ name: 'Test' });
});
expect( getClient.name ).to.equal( 'Test' );
});
after( function() {
server.execute( function() {
let client = Clients.findOne( { name: 'Test' } );
if ( client ) {
Clients.remove( client._id );
}
});
});
});
});
This is throwing an error that Clients is undefined
However, if I add
import { Clients } from '/imports/api/clients/clients.js';
I get this error Error: Cannot find module '/imports/api/clients/clients.js'
What am I doing wrong? Should I be using chimp? Any help would really be appreciated because I don't find the Meteor guide very clear about this!
Thanks
You need to use require like this:
require('/imports/api/clients/clients').Clients
See here for an example.

Tests are failing after Angular 2 RC5

I had used the following format for my tests:
export function main() {
describe('Angular2 component test', function() {
it('should initialize component',
async(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
var template = '<specific-component-tag>';
return tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
expect(fixture.componentInstance.viewChild).toBeDefined();
fixture.detectChanges();
expect(fixture.componentInstance.viewChild.items.length).toBe(1);
// .... etc.
}).catch (reason => {
console.log(reason);
return Promise.reject(reason);
});
})));
});
}
This work fine in RC4. But RC5 came suddenly and now this code have not worked.
It throws me the following errors:
Module ".... #angular/core/testing" has no exported member 'it'.
Module ".... #angular/core/testing" has no exported member 'describe'.
Module ".... #angular/core/testing" has no exported member 'expect'.
Module ".... #angular/core/testing" has no exported member 'beforeEachProviders'.
Module ".... #angular/compiler/testing" has no exported member 'TestComponentBuilder'.
Module ".... #angular/compiler/testing" has no exported member 'ComponentFixture'.
Please help me to migrate this test to angular2 RC5.
Update:
I have already read RC5 release notes but nothing comes to my mind how to achieve my goal.
The Jasmine imports available through #angular/core/testing are removed. So remove the imports for the following
Before:
import {
beforeEach,
beforeEachProviders,
describe,
expect,
it,
inject,
} from '#angular/core/testing';
after
/// <reference path="../../../typings/main/ambient/jasmine/index.d.ts" />
import {
inject, addProviders
} from '#angular/core/testing';
The reference path should be the first line in the file and it should point to jasmine type definition file. (Update the relative up. i.e the ../../ to whatever)To get jasmine type defitions, add the following line to ambientDevDependencies. Mine looks something like this
{
"ambientDevDependencies": {
"angular-protractor": "registry:dt/angular-protractor#1.5.0+20160425143459",
"jasmine": "registry:dt/jasmine#2.2.0+20160412134438",
"selenium-webdriver": "registry:dt/selenium-webdriver#2.44.0+20160317120654"
},
"ambientDependencies": {
"es6-shim": "registry:dt/es6-shim#0.31.2+20160317120654"
}
}
Also change
beforeEachProviders(() => [InMemoryDataService]);
to
import { TestBed } from '#angular/core/testing';
...
describe('...', () => {
TestBed.configureTestingModule({
providers: [ InMemoryDataService ]
});
it(...);
});
Take a look at changelog:
https://github.com/angular/angular/blob/master/CHANGELOG.md
It looks like API, which you are using is deprecated - path and names has changed. :)
For example:
TestComponentBuilder and ComponentFixture is now in #angular/core/testing,
beforeEachProviders:
code:
beforeEachProviders(() => [MyService]);
changed to:
beforeEach(() => {
addProviders([MyService]);
});
If you already read their release note. It's a lot of change in testing API package.
https://github.com/angular/angular/blob/master/CHANGELOG.md#breaking-changes
So, I didn't try to migrate test to RC5 yet. But I found link about change to new testing API.
https://ng2-info.github.io/2016/08/angular-2-rc-5/#テスティングapiに関する変更
Hope this help.