Getting a promise instead of the data i receive from pinia store - pinia

I have succesfully fetched data from an api into my pinia store, I am getting back the json data, when i call the action from my nuxt3 component, im getting a promise.
My store:
import { defineStore } from 'pinia';
export const useCountriesStore = defineStore("countries", {
state: () => ({
countries: [],
isLoading: false
}),
actions: {
async fetchCountries() {
this.isLoading = true;
const res = await fetch('https://restcountries.com/v3.1/all')
const data = await res.json();
this.countries = data;
console.log(data);
this.isLoading = false;
}
},
getters: {
getCountries: (state) => state.countries
}
})
My nuxt component:
<script lang="ts">
import { useCountriesStore } from '#/stores/countriesStore';
export default {
setup(){
const countriesStore = useCountriesStore();
const countriesData = countriesStore.fetchCountries();
console.log(countriesData)
}
}
</script>
This is the link to my github branch: https://github.com/AbbyNyakara/CountriesDirectory/tree/add-store
p/s: I have attached a screenshot of the data when i console log my store vs component
I have tried to fetch the data from my pinia store unsuccesfully

You are missing a return value in action fetchCountries
async fetchCountries() {
this.isLoading = true;
const res = await fetch('https://restcountries.com/v3.1/all')
const data = await res.json();
this.countries = data;
console.log(data);
this.isLoading = false;
return data;
}
And wait for the execution using async / await
<script lang="ts">
import { useCountriesStore } from '#/stores/countriesStore';
export default {
async setup(){
const countriesStore = useCountriesStore();
const countriesData = await countriesStore.fetchCountries();
console.log(countriesData)
}
}
</script>

Related

Proper way to test type-graphql middleware with jest

Context
I am trying to write a jest test for an authentication middleware for a resolver function. I am attempting to mock an implementation so that the next function is called so that the test passes.
Error
The error I receive is "next is not a function". I can verify that the mocked function is called through expect(isAuth).toHaveBeenCalledTimes(1);, but there is clearly an issue with my mocked implementation. Any help is much appreciated.
Code
//isAuth Middleware
import { MiddlewareFn } from "type-graphql";
import { Context } from "../utils/interfaces/context";
export const isAuth: MiddlewareFn<Context> = ({ context }, next) => {
const loggedInUserId = context.req.session.id;
if (!loggedInUserId) {
throw new Error("Not authenticated!");
}
return next();
};
//transaction.test.ts
jest.mock("../middleware/isAuth", () => {
return {
isAuth: jest.fn((_, next) => next()), //also tried (next) => next() and (next)=>Promise.resolve(next())
};
});
test("should create a txn successfully", async () => {
//ARRANGE
const user = await createUser(orm);
const txn = createTxnOptions();
const txnToBeCreated = { ...txn, userId: user.id };
//ACT
const response = await testClientMutate(
TXN_QUERIES_AND_MUTATIONS.CREATE_TXN,
{
variables: txnToBeCreated,
}
);
//expect(isAuth).toHaveBeenCalledTimes(1); passes so it's getting called
console.log(response);
const newlyCreatedTxn: Transaction = (response.data as any)
?.createTransaction;
//ASSERT
const dbTxn = await em.findOne(Transaction, {
id: newlyCreatedTxn.id,
});
expect(newlyCreatedTxn.id).toBe(dbTxn?.id);
});
//transaction.resolver.ts
import { Transaction } from "../entities/Transaction";
import {
Arg,
Ctx,
Mutation,
Query,
Resolver,
UseMiddleware,
} from "type-graphql";
import { Context } from "../utils/interfaces/context";
import { isAuth } from "../middleware/isAuth";
#Mutation(() => Transaction)
#UseMiddleware(isAuth)
async createTransaction(
#Arg("title") title: string,
#Arg("userId") userId: string,
#Ctx() { em }: Context
): Promise<Transaction> {
const transaction = em.create(Transaction, {
title,
user: userId,
});
await em.persistAndFlush(transaction);
return transaction;
}
Replace
jest.mock("../middleware/isAuth", () => {
return {
isAuth: jest.fn((_, next) => next()), //also tried (next) => next() and (next)=>Promise.resolve(next())
};
});
With
jest.mock("../middleware/isAuth", () => {
return {
isAuth: (_, next) => next()
};
});

hapi authentication strategy karma test with sinon with async function

I am trying to test the authentication scheme with hapi server. I have two helper function within the same file where I put my authentication scheme. I want to test when this successfully authenticate the user. But in my test case I always get 401 which is the unauthenicated message.
export const hasLegitItemUser = async (request, email, id) => {
const {
status,
payload: {users}
} = await svc.getRel(request, email);
if (status !== STATUS.OK) {
return false;
}
return users.includes(user)
};
export const getUser = async request => {
const token = request.state._token;
const res = await svc.validateToken({request, token});
const {
userInfo: {email}
} = res;
const id = extractId(request.path);
const isLetgitUser = await hasLegitItemUser(
request,
email,
id
);
res.isLegitUser = isLegitUser;
return res;
};
const scheme = (server, options) => {
server.state("my_sso", options.cookie);
server.ext("onPostAuth", (request, h) => {
return h.continue;
});
return {
async authenticate(request, h) {
try {
const {
tokenValid,
isLegitUser,
userInfo
} = await getUser(request);
if (tokenValid && isLegitUser) {
request.state["SSO"] = {
TOKEN: request.state._token
};
return h.authenticated({
credentials: {
userInfo
}
});
} else {
throw Boom.unauthorized(null,"my_auth");
}
} catch (err) {
throw Boom.unauthorized(null, "my_auth");
}
}
};
};
My Test file:
import Hapi from "hapi";
import sinon from "sinon";
import auth, * as authHelpers from "server/auth";
import {expect} from "chai";
import pcSvc from "server/plugins/services/pc-svc";
describe("Authentication Plugin", () => {
const sandbox = sinon.createSandbox();
const server = new Hapi.Server();
const authHandler = request => ({
credentials: request.auth.credentials,
artifacts: "boom"
});
before(() => {
server.register({
plugin: auth,
});
const route = ["/mypage/{id}/home"];
route.forEach(path => {
server.route({
method: "GET",
path,
options: {
auth: auth,
handler:{}
}
});
});
});
afterEach(() => {
sandbox.restore();
});
it("should authorize user if it is a validated user", async () => {
sandbox
.stub(authHelpers, "getUser")
.withArgs(request)
.resolves({
tokenValid: true,
isLegitUser: true,
userInfo: {}
});
return server
.inject({
method: "GET",
url:
"/mypage/888/home"
})
.then(res => {
expect(res.statusCode).to.equal(200);
expect(res.result).to.eql({
userInfo: {
email: "abc#gmail.com",
rlUserId: "abc",
userId: "abc#gmail.com"
}
});
});
});
});
I always get the 401 error for unauthenticated. It seems like my "getUser" function in my test is not triggering for some reason, it goes straight to the throw statement in the catch phase in my code. Please help.

Unit Test: How can i correctly trigger a trigger event on an input which calls a function in vuex?

i have this bootstrap vue component:
<b-form-input
v-model="currentUser.name"
placeholder="Name *"
name="name"
#input="checkSubmitStatus()"
></b-form-input>
checkSubmitStatus in the methods goes to call updateSubmitDisabled which I have in the mutations inside another file:
methods: {
...mapMutations({
updateSubmitDisabled: "updateSubmitDisabled"
}),
checkSubmitStatus() {
const isDisabled = this.currentUser.name.length === 0;
this.updateSubmitDisabled(isDisabled);
}
}
this is the .spec.js file:
import { createLocalVue, mount } from "#vue/test-utils";
import Vue from "vue";
import Vuex from 'vuex';
import UserForm from "#/components/event-created/UserForm.vue";
import { BootstrapVue, BootstrapVueIcons } from "bootstrap-vue";
const localVue = createLocalVue();
localVue.use(BootstrapVue);
localVue.use(BootstrapVueIcons);
localVue.use(Vuex);
describe("UserForm.vue", () => {
let mutations;
let store;
beforeEach(() => {
mutations = {
updateSubmitDisabled: jest.fn()
};
store = new Vuex.Store({
state: {
currentUser: {
name: 'pippo',
}
},
mutations
});
})
it("should call the updateSubmitDisabled mutation", async () => {
const wrapper = mount(UserForm, { localVue, store });
const input = wrapper.get('input[name="name"]');
await Vue.nextTick();
input.element.value = 'Test';
await input.trigger('input');
await Vue.nextTick();
expect(mutations.updateSubmitDisabled).toHaveBeenCalled();
});
});
for now I just want to test if "updateSubmitDisabled" is called on "name" but as a result the test says:
Expected number of calls:> = 1
Received number of calls: 0
I finally settled with:
it("should call the updateSubmitDisabled mutation", () => {
const wrapper = mount(UserForm, { localVue, store });
const input = wrapper.get('input[name="name"]');
input.element.dispatchEvent(new Event('input'));
expect(mutations.updateSubmitDisabled).toHaveBeenCalled();
});

Expo: MediaLibrary.createAlbumAsync is creating multiple album with same name

my function:
async function takePhotoNStore(){
if(cameraRef){
let picture = await cameraRef.current.takePictureAsync();
const asset = await MediaLibrary.createAssetAsync(picture.uri);
await MediaLibrary.createAlbumAsync('Expo', asset, false);
}
}
I'm trying to create one album named "Expo" but it keeps creating multiple "Expo" album every time I take a new picture.
You need to check if the album already exists with :
MediaLibrary.getAlbumAsync(albumName)
If this is the case, you can add your assets with :
MediaLibrary.addAssetsToAlbumAsync(assets, album, copyAssets)
If not, create it like you did.
You won't have any duplication! :)
For future reference
_saveToCameraRollAsync = async () => {
try {
let result = await captureRef(this.pageView, {
format: 'png',
quality: 0.9
});
const cachedAsset = await MediaLibrary.createAssetAsync(result);
// saved the asset uri
const album = await MediaLibrary.getAlbumAsync('GWA');
// check if the album if exist if return null you need to create an album.
if (album === null) {
// insert an album name with image
const asset = await MediaLibrary.createAssetAsync(result);
MediaLibrary.createAlbumAsync('GWA', asset)
.then(() => {
console.log('Album created!');
Alert.alert('Image has been saved')
this.setState({ cameraRollUri: asset });
})
.catch(error => {
Alert.alert(`Opps there's something wrong`)
console.log('err', error);
});
} else {
// if album exist asset added
let assetAdded = await MediaLibrary.addAssetsToAlbumAsync(
[cachedAsset],
album,
false
);
if (assetAdded === true) {
this.getAssetFromAlbum(album);
} else {
console.log("ASSET ADD ERROR");
}
}
}
catch (snapshotError) {
console.error(snapshotError);
}
};
getAssetFromAlbum = async album => {
//function
const assetResult = await MediaLibrary.getAssetsAsync({
first: 1,
album: album,
sortBy: MediaLibrary.SortBy.creationTime,
});
const asset = await assetResult.assets[0];
this.setState({ image_uri: asset.uri });
};
saveFile = async (fileUri) => {
const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
if (status === "granted") {
const cachedAsset = await MediaLibrary.createAssetAsync(fileUri);
const albumName = "xyz';
const album = await MediaLibrary.getAlbumAsync(albumName)
if(album){
await MediaLibrary.addAssetsToAlbumAsync([cachedAsset], album, false);
}else{
const asset = await MediaLibrary.createAssetAsync(fileUri);
await MediaLibrary.createAlbumAsync(albumName, asset);
}
}
};

Apollo: Update React Props on Subscription Update?

Looking at the Apollo docs example code for subscriptions, I am not yet seeing how to update the React props with the subscription results.
From http://dev.apollodata.com/react/subscriptions.html:
Here is a regular query:
import { CommentsPage } from './comments-page.js';
import { graphql } from 'react-apollo';
import gql from 'graphql-tag';
const COMMENT_QUERY = gql`
query Comment($repoName: String!) {
entry(repoFullName: $repoName) {
comments {
id
content
}
}
}
`;
const withData = graphql(COMMENT_QUERY, {
name: 'comments',
options: ({ params }) => ({
variables: {
repoName: `${params.org}/${params.repoName}`
},
})
});
export const CommentsPageWithData = withData(CommentsPage);
Now, let’s add the subscription.
Note that this sample code appears to leave out this part of the props code for usual queries - from http://dev.apollodata.com/react/queries.html:
props: ({ ownProps, data: { loading, currentUser, refetch } }) => ({
userLoading: loading,
user: currentUser,
refetchUser: refetch,
}),
...which AFAIK is the correct way to update the data props on my React component and trigger a page refresh.
Here is the complete subscription code sample from http://dev.apollodata.com/react/subscriptions.html:
const withData = graphql(COMMENT_QUERY, {
name: 'comments',
options: ({ params }) => ({
variables: {
repoName: `${params.org}/${params.repoName}`
},
}),
props: props => {
return {
subscribeToNewComments: params => {
return props.comments.subscribeToMore({
document: COMMENTS_SUBSCRIPTION,
variables: {
repoName: params.repoFullName,
},
updateQuery: (prev, {subscriptionData}) => {
if (!subscriptionData.data) {
return prev;
}
const newFeedItem = subscriptionData.data.commentAdded;
return Object.assign({}, prev, {
entry: {
comments: [newFeedItem, ...prev.entry.comments]
}
});
}
});
}
};
},
});
How do I get the code shown here, to update the data props on my React component and trigger a page refresh, when the results come in from the non-subscription query COMMENT_QUERY?
Thanks to #neophi on the Apollo Slack for this answer!
const withDataAndSubscription = graphql(GETIMS_QUERY, {
options({toID}) {
console.log(GETIMS_QUERY);
const fromID = Meteor.userId();
return {
fetchPolicy: 'cache-and-network',
variables: {fromID: `${fromID}`, toID: `${toID}`}
};
}
,
props: props => {
return {
loading: props.data.loading,
instant_message: props.data.instant_message,
subscribeToMore: props.data.subscribeToMore,
subscribeToNewIMs: params => {
const fromID = Meteor.userId();
const toID = params.toID;
return props.data.subscribeToMore({
document: IM_SUBSCRIPTION_QUERY,
variables: {fromID: `${fromID}`, toID: `${toID}`},
updateQuery: (previousResult, {subscriptionData}) => {
if (!subscriptionData.data) {
return previousResult;
}
const newMsg = subscriptionData.data.createIM;
return update(previousResult, {
instant_message: {
$push: [newMsg],
},
});
}
});
}
};
},
})
;