Skip to content

Commit 8fcd55c

Browse files
committed
Bugfixes, Refactorings and first integration test
1 parent be25c30 commit 8fcd55c

File tree

5 files changed

+153
-20
lines changed

5 files changed

+153
-20
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,12 @@
6464
"babel-preset-stage-2": "^6.24.1",
6565
"codecov.io": "^0.1.6",
6666
"expect": "^22.1.0",
67+
"fetch-mock": "^6.3.0",
6768
"fork-ts-checker-webpack-plugin": "^0.3.0",
6869
"istanbul-instrumenter-loader": "^3.0.0",
6970
"mocha": "^4.1.0",
7071
"mocha-webpack": "^1.0.1",
72+
"node-fetch": "^2.1.1",
7173
"nyc": "^11.4.1",
7274
"rollup": "^0.55.3",
7375
"rollup-plugin-commonjs": "^8.3.0",

src/vuex-orm-apollo.ts

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,15 @@ export default class VuexORMApollo {
103103
* @param {any} dispatch
104104
* @returns {Promise<void>}
105105
*/
106-
private async fetch ({ state, dispatch, filter }: ActionParams) {
106+
private async fetch ({ state, dispatch }: ActionParams, filter: ActionParams) {
107107
// When the filter contains an id, we query in singular mode
108-
const multiple: boolean = !(filter && filter.get('id'));
108+
const multiple: boolean = !(filter && filter['id']);
109109
const model: Model = this.getModel(state.$name);
110110
const name: string = `${multiple ? model.pluralName : model.singularName}`;
111111
const query = this.queryBuilder.buildQuery('query', name, filter, model.singularName);
112112

113113
// Send the request to the GraphQL API
114-
const data = await this.apolloRequest(query);
114+
const data = await this.apolloRequest(query, filter);
115115

116116
// Insert incoming data into the store
117117
await this.insertData(data, dispatch);
@@ -196,10 +196,7 @@ export default class VuexORMApollo {
196196
const query = this.queryBuilder.buildQuery('mutation', mutationName, { id }, model);
197197

198198
// Send GraphQL Mutation
199-
await this.apolloClient.mutate({
200-
mutation: query,
201-
variables: { where: id }
202-
});
199+
await this.apolloRequest(query, { where: id }, true);
203200
}
204201
}
205202

@@ -225,27 +222,27 @@ export default class VuexORMApollo {
225222
if (id) variables['id'] = id;
226223

227224
// Send GraphQL Mutation
228-
const response = await this.apolloClient.mutate({
229-
mutation: query,
230-
variables
231-
});
232-
233-
// Insert incoming data into the store
234-
const newData = this.queryBuilder.transformIncomingData(response.data as Data, true);
225+
const newData = await this.apolloRequest(query, variables, true);
235226
return this.updateData(newData, dispatch, data.id);
236227
}
237228
}
238229

239230
/**
240-
* Sends a query to the GraphQL API via apollo
231+
* Sends a request to the GraphQL API via apollo
241232
* @param query
242233
* @returns {Promise<Data>}
243234
*/
244-
private async apolloRequest (query: any): Promise<Data> {
245-
const response = await (this.apolloClient).query({ query });
235+
private async apolloRequest (query: any, variables?: Arguments, mutation:boolean = false): Promise<Data> {
236+
let response;
237+
238+
if (mutation) {
239+
response = await (this.apolloClient).mutate({ mutation: query, variables });
240+
} else {
241+
response = await (this.apolloClient).query({ query, variables });
242+
}
246243

247244
// Transform incoming data into something useful
248-
return this.queryBuilder.transformIncomingData(response.data);
245+
return this.queryBuilder.transformIncomingData(response.data as Data, mutation);
249246
}
250247

251248
/**
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,82 @@
1+
import {Model as ORMModel} from "@vuex-orm/core";
2+
import Vue from 'vue';
3+
import {createStore, sendWithMockFetch} from "../support/Helpers";
4+
import fetchMock from 'fetch-mock';
5+
6+
let store;
7+
18
describe('VuexORMApollo', () => {
9+
class User extends ORMModel {
10+
static entity = 'users';
11+
12+
static fields () {
13+
return {
14+
id: this.attr(null),
15+
name: this.attr(null),
16+
posts: this.hasMany(Post, 'userId')
17+
};
18+
}
19+
}
20+
21+
class Post extends ORMModel {
22+
static entity = 'posts';
23+
24+
static fields () {
25+
return {
26+
id: this.attr(null),
27+
title: this.attr(null),
28+
content: this.attr(null),
29+
userId: this.attr(null),
30+
user: this.belongsTo(User, 'userId')
31+
};
32+
}
33+
}
34+
35+
beforeEach(() => {
36+
store = createStore([{ model: User }, { model: Post }]);
37+
store.dispatch('entities/users/insert', { data: { id: 1, name: 'Johnny Imba' }});
38+
store.dispatch('entities/posts/insert', { data: { id: 1, title: 'Example Post 1', content: 'Foo', userId: 1 }});
39+
store.dispatch('entities/posts/insert', { data: { id: 2, title: 'Example Post 2', content: 'Bar', userId: 1 }});
40+
});
41+
42+
describe('fetch', () => {
43+
describe('with ID', () => {
44+
it('sends the correct query to the API', async () => {
45+
const response = {
46+
data: {
47+
user: {
48+
__typename: 'user',
49+
id: 1,
50+
name: 'Johnny Imba',
51+
posts: {
52+
__typename: 'post',
53+
nodes: [
54+
{
55+
__typename: 'post',
56+
id: 1,
57+
userId: 1,
58+
title: 'Example Post 1',
59+
content: 'Foo'
60+
},
61+
{
62+
__typename: 'post',
63+
id: 2,
64+
userId: 1,
65+
title: 'Example Post 2',
66+
content: 'Bar'
67+
}
68+
]
69+
}
70+
}
71+
}
72+
};
73+
74+
const request = await sendWithMockFetch(response, async () => {
75+
await store.dispatch('entities/users/fetch', { id: 1 });
76+
});
277

78+
expect(request.variables).toEqual({ id: 1 });
79+
});
80+
})
81+
});
382
});

test/support/Helpers.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,59 @@ import _ from 'lodash';
22
import Vue from 'vue';
33
import Vuex from 'vuex';
44
import VuexORM, { Database, Model } from '@vuex-orm/core';
5-
// import installVuexORMApollo from 'app';
5+
import installVuexORMApollo from 'app';
6+
import fetchMock from 'fetch-mock';
67

78
Vue.use(Vuex);
89

10+
let fetchMockSetupDone = false;
11+
912
/**
1013
* Create a new Vuex Store.
1114
*/
1215
export function createStore (entities) {
1316
const database = new Database();
1417

18+
if (!fetchMockSetupDone) {
19+
fetchMock.get('*', {});
20+
fetchMockSetupDone = true;
21+
}
22+
1523
_.forEach(entities, (entity) => {
1624
database.register(entity.model, entity.module || {})
1725
});
1826

19-
// VuexORM.use(installVuexORMApollo, { database: database });
27+
VuexORM.use(installVuexORMApollo, { database: database });
2028

2129
return new Vuex.Store({
2230
plugins: [VuexORM.install(database)]
2331
});
2432
}
33+
34+
35+
36+
export async function sendWithMockFetch(response, callback) {
37+
fetchMock.post('/graphql', response);
38+
39+
try {
40+
await callback();
41+
} catch (error) {
42+
console.error("An error occured:");
43+
console.error(error);
44+
throw new Error("Request failed!");
45+
}
46+
47+
const request = fetchMock.lastCall();
48+
fetchMock.restore();
49+
50+
/*
51+
Generates
52+
53+
{
54+
operationName: "Users",
55+
query: "query Users {\n users {\n nodes {\n id\n name\n posts {\n nodes {\n id\n title\n content\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n"
56+
variables: {}
57+
}
58+
*/
59+
return JSON.parse(request[1].body);
60+
}

yarn.lock

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1765,6 +1765,13 @@ fast-json-stable-stringify@^2.0.0:
17651765
version "2.0.0"
17661766
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
17671767

1768+
fetch-mock@^6.3.0:
1769+
version "6.3.0"
1770+
resolved "https://registry.yarnpkg.com/fetch-mock/-/fetch-mock-6.3.0.tgz#4fcf710e49e6202c951d0d7ba8d4a862b6321cef"
1771+
dependencies:
1772+
glob-to-regexp "^0.4.0"
1773+
path-to-regexp "^2.1.0"
1774+
17681775
filename-regex@^2.0.0:
17691776
version "2.0.1"
17701777
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
@@ -1957,6 +1964,10 @@ glob-parent@^2.0.0:
19571964
dependencies:
19581965
is-glob "^2.0.0"
19591966

1967+
glob-to-regexp@^0.4.0:
1968+
version "0.4.0"
1969+
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.0.tgz#49bd677b1671022bd10921c3788f23cdebf9c7e6"
1970+
19601971
[email protected], glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1:
19611972
version "7.1.2"
19621973
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
@@ -2914,6 +2925,10 @@ nise@^1.2.0:
29142925
path-to-regexp "^1.7.0"
29152926
text-encoding "^0.6.4"
29162927

2928+
node-fetch@^2.1.1:
2929+
version "2.1.1"
2930+
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.1.tgz#369ca70b82f50c86496104a6c776d274f4e4a2d4"
2931+
29172932
node-libs-browser@^2.0.0:
29182933
version "2.1.0"
29192934
resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df"
@@ -3219,6 +3234,10 @@ path-to-regexp@^1.7.0:
32193234
dependencies:
32203235
isarray "0.0.1"
32213236

3237+
path-to-regexp@^2.1.0:
3238+
version "2.2.0"
3239+
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.0.tgz#80f0ff45c1e0e641da74df313644eaf115050972"
3240+
32223241
path-type@^1.0.0:
32233242
version "1.1.0"
32243243
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"

0 commit comments

Comments
 (0)