Browse Source

Update of the whole app

Phyks (Lucas Verney) 2 years ago
parent
commit
b57bdb6b7b

+ 0
- 1
index.html View File

@@ -3,7 +3,6 @@
3 3
   <head>
4 4
     <meta charset="utf-8">
5 5
     <title>HungerGames</title>
6
-    <link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' rel="stylesheet">
7 6
     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
8 7
   </head>
9 8
   <body>

+ 379
- 2261
package-lock.json
File diff suppressed because it is too large
View File


+ 18
- 33
package.json View File

@@ -16,75 +16,60 @@
16 16
   "dependencies": {
17 17
     "es6-promise": "^4.1.1",
18 18
     "isomorphic-fetch": "^2.2.1",
19
-    "vue": "^2.5.2",
19
+    "material-design-icons": "^3.0.1",
20
+    "vue": "^2.5.8",
20 21
     "vue-router": "^3.0.1",
21
-    "vuetify": "^0.16.9",
22
-    "vuex": "^3.0.0"
22
+    "vuetify": "^0.17.2",
23
+    "vuex": "^3.0.1"
23 24
   },
24 25
   "devDependencies": {
25 26
     "autoprefixer": "^7.1.6",
26 27
     "babel-core": "^6.22.1",
27
-    "babel-eslint": "^8.0.1",
28
+    "babel-eslint": "^8.0.2",
28 29
     "babel-loader": "^7.1.1",
29 30
     "babel-plugin-istanbul": "^4.1.1",
30 31
     "babel-plugin-transform-runtime": "^6.22.0",
31 32
     "babel-preset-env": "^1.6.1",
32 33
     "babel-preset-stage-2": "^6.22.0",
33 34
     "babel-register": "^6.22.0",
34
-    "chai": "^4.1.2",
35
-    "chalk": "^2.2.0",
36
-    "chromedriver": "^2.33.2",
37
-    "connect-history-api-fallback": "^1.4.0",
38
-    "copy-webpack-plugin": "^4.2.0",
39
-    "cross-env": "^5.1.0",
35
+    "connect-history-api-fallback": "^1.5.0",
36
+    "copy-webpack-plugin": "^4.2.1",
37
+    "cross-env": "^5.1.1",
40 38
     "cross-spawn": "^5.0.1",
41 39
     "css-loader": "^0.28.0",
42 40
     "cssnano": "^3.10.0",
43
-    "eslint": "^4.9.0",
41
+    "eslint": "^4.11.0",
44 42
     "eslint-config-airbnb-base": "^12.1.0",
45 43
     "eslint-friendly-formatter": "^3.0.0",
46 44
     "eslint-import-resolver-webpack": "^0.8.1",
47 45
     "eslint-loader": "^1.7.1",
48
-    "eslint-plugin-html": "^3.0.0",
46
+    "eslint-plugin-html": "^4.0.0",
49 47
     "eslint-plugin-import": "^2.8.0",
50 48
     "eventsource-polyfill": "^0.9.6",
51 49
     "express": "^4.16.2",
52
-    "extract-text-webpack-plugin": "^3.0.1",
50
+    "extract-text-webpack-plugin": "^3.0.2",
53 51
     "file-loader": "^1.1.5",
54 52
     "friendly-errors-webpack-plugin": "^1.1.3",
55 53
     "html-webpack-plugin": "^2.28.0",
56 54
     "http-proxy-middleware": "^0.17.3",
57 55
     "inject-loader": "^3.0.0",
58
-    "karma": "^1.4.1",
59
-    "karma-coverage": "^1.1.1",
60
-    "karma-mocha": "^1.3.0",
61
-    "karma-phantomjs-launcher": "^1.0.2",
62
-    "karma-phantomjs-shim": "^1.4.0",
63
-    "karma-sinon-chai": "^1.3.1",
64
-    "karma-sourcemap-loader": "^0.3.7",
65
-    "karma-spec-reporter": "0.0.31",
66
-    "karma-webpack": "^2.0.5",
67
-    "mocha": "^4.0.1",
68
-    "nightwatch": "^0.9.12",
69 56
     "opn": "^5.1.0",
70 57
     "optimize-css-assets-webpack-plugin": "^3.2.0",
71 58
     "ora": "^1.2.0",
72
-    "phantomjs-prebuilt": "^2.1.14",
59
+    "phantomjs-prebuilt": "^2.1.16",
73 60
     "rimraf": "^2.6.0",
74
-    "selenium-server": "^3.6.0",
61
+    "selenium-server": "^3.7.1",
75 62
     "semver": "^5.3.0",
76
-    "shelljs": "^0.7.6",
77
-    "sinon": "^4.0.1",
78
-    "sinon-chai": "^2.14.0",
63
+    "shelljs": "^0.7.8",
79 64
     "url-loader": "^0.6.2",
80
-    "vue-loader": "^13.3.0",
65
+    "vue-loader": "^13.5.0",
81 66
     "vue-style-loader": "^3.0.1",
82
-    "vue-template-compiler": "^2.5.2",
67
+    "vue-template-compiler": "^2.5.8",
83 68
     "webpack": "^3.8.1",
84
-    "webpack-bundle-analyzer": "^2.2.1",
69
+    "webpack-bundle-analyzer": "^2.9.1",
85 70
     "webpack-dev-middleware": "^1.10.0",
86 71
     "webpack-hot-middleware": "^2.20.0",
87
-    "webpack-merge": "^4.1.0"
72
+    "webpack-merge": "^4.1.1"
88 73
   },
89 74
   "engines": {
90 75
     "node": ">= 4.0.0",

+ 12
- 10
src/App.vue View File

@@ -1,19 +1,13 @@
1 1
 <template>
2
-    <v-app toolbar>
2
+    <v-app>
3 3
         <NavigationDrawer v-model="isDrawerVisible"/>
4 4
         <v-toolbar color="indigo" dark fixed app clipped-left>
5 5
             <v-toolbar-side-icon @click.stop="showHideDrawer"></v-toolbar-side-icon>
6 6
             <v-toolbar-title>HungerGames</v-toolbar-title>
7
-            <v-spacer></v-spacer>
8
-            <v-btn icon>
9
-                <v-icon>skip_next</v-icon>
10
-            </v-btn>
11 7
         </v-toolbar>
12
-        <main>
13
-            <v-content>
14
-                <router-view></router-view>
15
-            </v-content>
16
-        </main>
8
+        <v-content class="max-width">
9
+            <router-view></router-view>
10
+        </v-content>
17 11
     </v-app>
18 12
 </template>
19 13
 
@@ -36,3 +30,11 @@ export default {
36 30
     },
37 31
 };
38 32
 </script>
33
+
34
+<style scoped>
35
+.max-width {
36
+    max-width: 1000px;
37
+    margin-left: auto;
38
+    margin-right: auto;
39
+}
40
+</style>

+ 24
- 5
src/api/index.js View File

@@ -1,15 +1,33 @@
1 1
 require('es6-promise').polyfill();
2 2
 require('isomorphic-fetch');
3 3
 
4
-export const BASEURL = 'https://world.openfoodfacts.org/';
4
+export const BASE_URL = 'https://world.openfoodfacts.org';
5
+export const BASE_FETCH_PARAMS = {
6
+    /*
7
+    credentials: 'include',
8
+    headers: {
9
+        Authorization: `Basic ${btoa('off:off')}`,
10
+    },
11
+    */
12
+};
13
+export const USER_ID = '';
14
+export const PASSWORD = '';
5 15
 
6 16
 function _fetchFromOFFApi(filters) {
7
-    let url = BASEURL;
17
+    let url = BASE_URL;
8 18
     filters.forEach((filter) => {
9 19
         url += `/${filter}`;
10 20
     });
11 21
 
12
-    return fetch(`${url}.json`);
22
+    return fetch(`${url}.json`, BASE_FETCH_PARAMS);
23
+}
24
+
25
+function _sendToOFFApi(barcode, fields) {
26
+    let url = `${BASE_URL}/cgi/product_jqmp2.pl?code=${barcode}&user_id=${USER_ID}&password=${PASSWORD}`;
27
+    Object.keys(fields).forEach((field) => {
28
+        url += `&${field}=${fields[field]}`;
29
+    });
30
+    return fetch(url, BASE_FETCH_PARAMS);
13 31
 }
14 32
 
15 33
 function missingCategories() {
@@ -60,8 +78,9 @@ function missingCategories() {
60 78
 
61 79
 
62 80
 function updateCategories(productId, categories) {
63
-    // TODO
64
-    console.log(productId, categories);
81
+    return _sendToOFFApi(productId, {
82
+        categories: categories.join(','),
83
+    });
65 84
 }
66 85
 
67 86
 

+ 24
- 0
src/components/About.vue View File

@@ -0,0 +1,24 @@
1
+<template>
2
+    <v-container fluid>
3
+        <v-layout row>
4
+            <v-flex xs12 class="text-xs-center">
5
+                <h2>About</h2>
6
+            </v-flex>
7
+        </v-layout>
8
+        <v-layout row>
9
+            <v-flex xs12>
10
+                <p>
11
+                    This app is a quest-based app to help you update and
12
+                    complete <a href="http://openfoodfacts.org/">OpenFoodFacts</a> data.
13
+                </p>
14
+                <p>This app is a free software, released under MIT license.</p>
15
+                <p>OpenFoodFacts database is a free database licensed under <a href="https://world.openfoodfacts.org/legal">Open Database License</a>.</p>
16
+            </v-flex>
17
+        </v-layout>
18
+    </v-container>
19
+</template>
20
+
21
+<script>
22
+export default {
23
+};
24
+</script>

+ 2
- 2
src/components/NavigationDrawer.vue View File

@@ -1,9 +1,9 @@
1 1
 <template>
2 2
     <v-navigation-drawer
3
-        persistent
3
+        fixed
4 4
         clipped
5 5
         app
6
-        enable-resize-watcher
6
+        disable-resize-watcher
7 7
         v-model="isActive"
8 8
         >
9 9
         <v-list>

+ 0
- 89
src/components/QuestMissingCategories/index.vue View File

@@ -1,89 +0,0 @@
1
-<template>
2
-    <v-container fluid grid-list-lg class="text-xs-center">
3
-        <v-layout row mb-3 align-center>
4
-            <v-flex xs5>
5
-                <v-dialog v-model="dialog" lazy absolute>
6
-                    <v-avatar
7
-                        size="100%"
8
-                        class="pointable"
9
-                        slot="activator"
10
-                        >
11
-                        <!-- TODO: Should be closable by ESC -->
12
-                        <img class="icon" :src="data.icon" />
13
-                    </v-avatar>
14
-                    <v-card>
15
-                        <v-card-text>
16
-                            <!-- TODO: Preload images -->
17
-                            <img style="width: 100%;" :src="data.icon" />
18
-                        </v-card-text>
19
-                    </v-card>
20
-                </v-dialog>
21
-            </v-flex>
22
-            <v-flex xs7 class="text-xs-center">
23
-                <div>
24
-                    <div class="headline">{{ data.brands || 'Unknown' }}</div>
25
-                    <h2 class="title">{{ data.name || 'Unkown' }}</h2>
26
-                </div>
27
-            </v-flex>
28
-        </v-layout>
29
-        <v-divider />
30
-        <v-layout row>
31
-            <v-flex xs12>
32
-                <h2 class="title">Select all correct categories:</h2>
33
-            </v-flex>
34
-        </v-layout>
35
-        <v-layout row wrap>
36
-            <v-btn
37
-                v-for="(category, key) in data.predictedCategories" :key="key"
38
-                round dark :class="{ green: category.isOK, red: !category.isOK }"
39
-                @click.stop="data.predictedCategories[key].isOK = !data.predictedCategories[key].isOK"
40
-                >
41
-                {{ category.name }}
42
-            </v-btn>
43
-        </v-layout>
44
-        <v-layout row>
45
-            <v-flex xs12>
46
-                <v-btn @click="handleSubmit()">Submit</v-btn>
47
-            </v-flex>
48
-        </v-layout>
49
-    </v-container>
50
-</template>
51
-
52
-<script>
53
-export default {
54
-    props: {
55
-        data: Object,
56
-        onSubmit: Function,
57
-    },
58
-    data() {
59
-        return {
60
-            dialog: false,
61
-        };
62
-    },
63
-    methods: {
64
-        handleSubmit() {
65
-            const okCategories = [];
66
-            Object.keys(this.data.predictedCategories).forEach((key) => {
67
-                if (this.data.predictedCategories[key].isOk) {
68
-                    okCategories.push(key);
69
-                }
70
-            });
71
-            this.onSubmit(okCategories);
72
-        },
73
-    },
74
-};
75
-</script>
76
-
77
-<style scoped>
78
-.pointable {
79
-    cursor: pointer;
80
-}
81
-
82
-.pointable:hover {
83
-    opacity: 0.8;
84
-}
85
-
86
-.icon {
87
-    border-radius: 0;
88
-}
89
-</style>

+ 66
- 0
src/components/Quests/QuestMissingCategories/index.vue View File

@@ -0,0 +1,66 @@
1
+<template>
2
+    <v-container fluid grid-list-lg class="text-xs-center">
3
+        <v-layout row mb-3 align-center>
4
+            <v-flex xs5>
5
+                <ZoomableImage :url="questData.icon" />
6
+            </v-flex>
7
+            <v-flex xs7 class="text-xs-center">
8
+                <div>
9
+                    <div class="headline">{{ questData.brands || 'Unknown' }}</div>
10
+                    <h2 class="title">{{ questData.name || 'Unkown' }}</h2>
11
+                </div>
12
+            </v-flex>
13
+        </v-layout>
14
+        <v-divider />
15
+        <v-layout row>
16
+            <v-flex xs12>
17
+                <h2 class="title">Select all correct categories:</h2>
18
+            </v-flex>
19
+        </v-layout>
20
+        <v-layout row wrap>
21
+            <v-btn
22
+                v-for="(category, key) in questData.predictedCategories" :key="key"
23
+                round dark :class="{ green: category.isOk, red: !category.isOk }"
24
+                @click.stop="handleClick(key)"
25
+                >
26
+                {{ category.name }}
27
+            </v-btn>
28
+        </v-layout>
29
+        <v-layout row>
30
+            <v-flex xs12>
31
+                <v-btn @click="handleSubmit()">Submit</v-btn>
32
+                or <a @click="onSkip()">Skip</a>
33
+            </v-flex>
34
+        </v-layout>
35
+    </v-container>
36
+</template>
37
+
38
+<script>
39
+import ZoomableImage from '@/components/ZoomableImage';
40
+
41
+export default {
42
+    components: {
43
+        ZoomableImage,
44
+    },
45
+    props: {
46
+        questData: Object,
47
+        onSubmit: Function,
48
+        onSkip: Function,
49
+    },
50
+    methods: {
51
+        handleSubmit() {
52
+            const okCategories = [];
53
+            Object.keys(this.questData.predictedCategories).forEach((key) => {
54
+                if (this.questData.predictedCategories[key].isOk) {
55
+                    okCategories.push(this.questData.predictedCategories[key].name);
56
+                }
57
+            });
58
+            this.onSubmit(okCategories);
59
+        },
60
+        handleClick(key) {
61
+            this.questData.predictedCategories[key].isOk =
62
+                !this.questData.predictedCategories[key].isOk;
63
+        },
64
+    },
65
+};
66
+</script>

+ 57
- 0
src/components/Quests/index.vue View File

@@ -0,0 +1,57 @@
1
+<template>
2
+    <div>
3
+        <v-layout row v-if="isLoading">
4
+            <v-flex xs12>
5
+                <p>Loading quests…</p>
6
+            </v-flex>
7
+        </v-layout>
8
+        <template v-else>
9
+            <QuestMissingCategories v-if="questData" :questData="questData" :onSubmit="validateQuest" :onSkip="skipQuest" />
10
+        </template>
11
+    </div>
12
+</template>
13
+
14
+<script>
15
+import QuestMissingCategories from '@/components/Quests/QuestMissingCategories/index';
16
+
17
+export default {
18
+    data() {
19
+        return {
20
+            isLoading: false,
21
+            error: null,
22
+        };
23
+    },
24
+    components: {
25
+        QuestMissingCategories,
26
+    },
27
+    created() {
28
+        this.fetchData();
29
+    },
30
+    methods: {
31
+        fetchData() {
32
+            this.isLoading = true;
33
+            this.$store.dispatch('preloadQuests').then(() => {
34
+                this.isLoading = false;
35
+            });
36
+        },
37
+        validateQuest(solution) {
38
+            this.$store.dispatch('validateQuest', {
39
+                type: this.questData.type,
40
+                id: this.questData.id,
41
+                solution,
42
+            });
43
+        },
44
+        skipQuest() {
45
+            this.$store.dispatch('skipQuest', {
46
+                type: this.questData.type,
47
+                id: this.questData.id,
48
+            });
49
+        },
50
+    },
51
+    computed: {
52
+        questData() {
53
+            return this.$store.getters.popQuest;
54
+        },
55
+    },
56
+};
57
+</script>

+ 72
- 0
src/components/ZoomableImage.vue View File

@@ -0,0 +1,72 @@
1
+<template>
2
+    <v-dialog v-model="dialog">
3
+        <v-avatar
4
+            size="100%"
5
+            class="pointable"
6
+            slot="activator"
7
+            >
8
+            <!-- TODO: Should be closable by ESC -->
9
+            <img class="icon" :src="url" />
10
+        </v-avatar>
11
+        <v-card>
12
+            <v-card-text>
13
+                <!-- TODO: Preload images -->
14
+                <img class="zoomed-image" :src="url" />
15
+            </v-card-text>
16
+        </v-card>
17
+    </v-dialog>
18
+</template>
19
+
20
+<script>
21
+export default {
22
+    props: {
23
+        url: String,
24
+    },
25
+    mounted() {
26
+        document.addEventListener('keydown', this.handleEscKey);
27
+    },
28
+    beforeDestroy() {
29
+        document.removeEventListener('keydown', this.handleEscKey);
30
+    },
31
+    methods: {
32
+        handleEscKey(e) {
33
+            if (
34
+                this.dialog && (
35
+                    e.key === 'Escape' ||
36
+                    e.key === 'Esc' ||
37
+                    e.keyCode === 27
38
+                )
39
+            ) {
40
+                this.dialog = false;
41
+            }
42
+        },
43
+    },
44
+    data() {
45
+        return {
46
+            dialog: false,
47
+        };
48
+    },
49
+};
50
+</script>
51
+
52
+<style scoped>
53
+.pointable {
54
+    cursor: pointer;
55
+}
56
+
57
+.pointable:hover {
58
+    opacity: 0.8;
59
+}
60
+
61
+.icon {
62
+    border-radius: 0;
63
+}
64
+
65
+.zoomed-image {
66
+    margin-left: auto;
67
+    margin-right: auto;
68
+    max-width: 100%;
69
+    max-height: 100%;
70
+    display: block;
71
+}
72
+</style>

+ 1
- 0
src/main.js View File

@@ -3,6 +3,7 @@
3 3
 import Vue from 'vue';
4 4
 import Vuetify from 'vuetify';
5 5
 import 'vuetify/dist/vuetify.min.css';
6
+import 'material-design-icons/iconfont/material-icons.css';
6 7
 
7 8
 import App from './App';
8 9
 import router from './router';

+ 4
- 3
src/router/index.js View File

@@ -1,7 +1,8 @@
1 1
 import Vue from 'vue';
2 2
 import Router from 'vue-router';
3
-import About from '@/views/About';
4
-import Quest from '@/views/Quest';
3
+
4
+import About from '@/components/About';
5
+import Quests from '@/components/Quests';
5 6
 
6 7
 Vue.use(Router);
7 8
 
@@ -10,7 +11,7 @@ export default new Router({
10 11
         {
11 12
             path: '/',
12 13
             name: 'Home',
13
-            component: Quest,
14
+            component: Quests,
14 15
         },
15 16
         {
16 17
             path: '/about',

+ 23
- 10
src/store/actions.js View File

@@ -4,25 +4,28 @@ import quests from './quests';
4 4
 
5 5
 export default {
6 6
     preloadQuests({ commit }) {
7
-        commit(types.IS_LOADING_QUESTS);
8
-
7
+        const apiRequests = [];
9 8
         Object.keys(quests).forEach((quest) => {
10
-            quests[quest]().then(
11
-                items => commit(
12
-                    types.STORE_QUESTS_ITEMS,
13
-                    {
14
-                        type: 'missingCategories',
15
-                        items,
16
-                    },
9
+            apiRequests.push(
10
+                quests[quest]().then(
11
+                    items => commit(
12
+                        types.STORE_QUESTS_ITEMS,
13
+                        {
14
+                            type: 'missingCategories',
15
+                            items,
16
+                        },
17
+                    ),
17 18
                 ),
18 19
             );
19 20
         });
21
+
22
+        return Promise.all(apiRequests);
20 23
     },
21 24
 
22 25
     validateQuest({ commit }, { type, id, solution }) {
23 26
         if (type === 'missingCategories') {
24 27
             updateCategories(id, solution).then(() => commit(
25
-                types.VALIDATE_QUEST,
28
+                types.REMOVE_QUEST_ITEM,
26 29
                 {
27 30
                     type,
28 31
                     id,
@@ -30,4 +33,14 @@ export default {
30 33
             ));
31 34
         }
32 35
     },
36
+
37
+    skipQuest({ commit }, { type, id }) {
38
+        commit(
39
+            types.REMOVE_QUEST_ITEM,
40
+            {
41
+                type,
42
+                id,
43
+            },
44
+        );
45
+    },
33 46
 };

+ 1
- 2
src/store/mutations-types.js View File

@@ -1,3 +1,2 @@
1
-export const IS_LOADING_QUESTS = 'IS_LOADING_QUESTS';
2 1
 export const STORE_QUESTS_ITEMS = 'STORE_QUESTS_ITEMS';
3
-export const VALIDATE_QUEST = 'VALIDATE_QUEST';
2
+export const REMOVE_QUEST_ITEM = 'REMOVE_QUEST_ITEM';

+ 5
- 6
src/store/mutations.js View File

@@ -3,20 +3,19 @@ import Vue from 'vue';
3 3
 import * as types from './mutations-types';
4 4
 
5 5
 export const initialState = {
6
-    isLoading: false,
7 6
     questsItems: {},
8 7
 };
9 8
 
10 9
 export const mutations = {
11
-    [types.IS_LOADING_QUESTS](state) {
12
-        state.isLoading = true;
13
-    },
14 10
     [types.STORE_QUESTS_ITEMS](state, { type, items }) {
15 11
         Vue.set(state.questsItems, type, items);
16 12
     },
17
-    [types.VALIDATE_QUEST](state, { id, type }) {
13
+    [types.REMOVE_QUEST_ITEM](state, { type, id }) {
18 14
         const items = state.questsItems[type];
19
-        delete items[id];
15
+        const index = items.findIndex(item => item.id === id);
16
+        if (index > -1) {
17
+            items.splice(index, 1);
18
+        }
20 19
         Vue.set(state.questsItems, type, items);
21 20
     },
22 21
 };

+ 0
- 19
src/views/About.vue View File

@@ -1,19 +0,0 @@
1
-<template>
2
-    <v-container fluid>
3
-        <v-layout row>
4
-            <v-flex xs12>
5
-                <h2>About</h2>
6
-            </v-flex>
7
-        </v-layout>
8
-        <v-layout row>
9
-            <v-flex xs12>
10
-                <p>TODO</p>
11
-            </v-flex>
12
-        </v-layout>
13
-    </v-container>
14
-</template>
15
-
16
-<script>
17
-export default {
18
-};
19
-</script>

+ 0
- 35
src/views/Quest.vue View File

@@ -1,35 +0,0 @@
1
-<template>
2
-    <QuestMissingCategories v-if="questData" :data="questData" :onSubmit="validateQuest" />
3
-</template>
4
-
5
-<script>
6
-import QuestMissingCategories from '@/components/QuestMissingCategories/index';
7
-
8
-
9
-// TODO: Changing route should not flash old product
10
-export default {
11
-    components: {
12
-        QuestMissingCategories,
13
-    },
14
-    created() {
15
-        this.fetchData();
16
-    },
17
-    methods: {
18
-        fetchData() {
19
-            this.$store.dispatch('preloadQuests');
20
-        },
21
-        validateQuest(solution) {
22
-            this.$store.dispatch('validateQuest', {
23
-                type: this.questData.type,
24
-                id: this.questData.id,
25
-                solution,
26
-            });
27
-        },
28
-    },
29
-    computed: {
30
-        questData() {
31
-            return this.$store.getters.popQuest;
32
-        },
33
-    },
34
-};
35
-</script>

+ 0
- 24
test/e2e/custom-assertions/elementCount.js View File

@@ -1,24 +0,0 @@
1
-// A custom Nightwatch assertion.
2
-// the name of the method is the filename.
3
-// can be used in tests like this:
4
-//
5
-//   browser.assert.elementCount(selector, count)
6
-//
7
-// for how to write custom assertions see
8
-// http://nightwatchjs.org/guide#writing-custom-assertions
9
-exports.assertion = function (selector, count) {
10
-    this.message = `Testing if element <${selector}> has count: ${count}`;
11
-    this.expected = count;
12
-    this.pass = function (val) {
13
-        return val === this.expected;
14
-    };
15
-    this.value = function (res) {
16
-        return res.value;
17
-    };
18
-    this.command = function (cb) {
19
-        const self = this;
20
-        return this.api.execute(selector => document.querySelectorAll(selector).length, [selector], (res) => {
21
-            cb.call(self, res);
22
-        });
23
-    };
24
-};

+ 0
- 46
test/e2e/nightwatch.conf.js View File

@@ -1,46 +0,0 @@
1
-require('babel-register');
2
-const config = require('../../config');
3
-
4
-// http://nightwatchjs.org/gettingstarted#settings-file
5
-module.exports = {
6
-    src_folders: ['test/e2e/specs'],
7
-    output_folder: 'test/e2e/reports',
8
-    custom_assertions_path: ['test/e2e/custom-assertions'],
9
-
10
-    selenium: {
11
-        start_process: true,
12
-        server_path: require('selenium-server').path,
13
-        host: '127.0.0.1',
14
-        port: 4444,
15
-        cli_args: {
16
-            'webdriver.chrome.driver': require('chromedriver').path,
17
-        },
18
-    },
19
-
20
-    test_settings: {
21
-        default: {
22
-            selenium_port: 4444,
23
-            selenium_host: 'localhost',
24
-            silent: true,
25
-            globals: {
26
-                devServerURL: `http://localhost:${process.env.PORT || config.dev.port}`,
27
-            },
28
-        },
29
-
30
-        chrome: {
31
-            desiredCapabilities: {
32
-                browserName: 'chrome',
33
-                javascriptEnabled: true,
34
-                acceptSslCerts: true,
35
-            },
36
-        },
37
-
38
-        firefox: {
39
-            desiredCapabilities: {
40
-                browserName: 'firefox',
41
-                javascriptEnabled: true,
42
-                acceptSslCerts: true,
43
-            },
44
-        },
45
-    },
46
-};

+ 0
- 33
test/e2e/runner.js View File

@@ -1,33 +0,0 @@
1
-// 1. start the dev server using production config
2
-process.env.NODE_ENV = 'testing';
3
-const server = require('../../build/dev-server.js');
4
-
5
-server.ready.then(() => {
6
-  // 2. run the nightwatch test suite against it
7
-  // to run in additional browsers:
8
-  //    1. add an entry in test/e2e/nightwatch.conf.json under "test_settings"
9
-  //    2. add it to the --env flag below
10
-  // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox`
11
-  // For more information on Nightwatch's config file, see
12
-  // http://nightwatchjs.org/guide#settings-file
13
-    let opts = process.argv.slice(2);
14
-    if (opts.indexOf('--config') === -1) {
15
-        opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js']);
16
-    }
17
-    if (opts.indexOf('--env') === -1) {
18
-        opts = opts.concat(['--env', 'chrome']);
19
-    }
20
-
21
-    const spawn = require('cross-spawn');
22
-    const runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' });
23
-
24
-    runner.on('exit', (code) => {
25
-        server.close();
26
-        process.exit(code);
27
-    });
28
-
29
-    runner.on('error', (err) => {
30
-        server.close();
31
-        throw err;
32
-    });
33
-});

+ 0
- 19
test/e2e/specs/test.js View File

@@ -1,19 +0,0 @@
1
-// For authoring Nightwatch tests, see
2
-// http://nightwatchjs.org/guide#usage
3
-
4
-module.exports = {
5
-    'default e2e tests': function test(browser) {
6
-    // automatically uses dev Server port from /config.index.js
7
-    // default: http://localhost:8080
8
-    // see nightwatch.conf.js
9
-        const devServer = browser.globals.devServerURL;
10
-
11
-        browser
12
-      .url(devServer)
13
-      .waitForElementVisible('#app', 5000)
14
-      .assert.elementPresent('.hello')
15
-      .assert.containsText('h1', 'Welcome to Your Vue.js App')
16
-      .assert.elementCount('img', 1)
17
-      .end();
18
-    },
19
-};

+ 0
- 9
test/unit/.eslintrc View File

@@ -1,9 +0,0 @@
1
-{
2
-  "env": {
3
-    "mocha": true
4
-  },
5
-  "globals": {
6
-    "expect": true,
7
-    "sinon": true
8
-  }
9
-}

+ 0
- 13
test/unit/index.js View File

@@ -1,13 +0,0 @@
1
-import Vue from 'vue';
2
-
3
-Vue.config.productionTip = false;
4
-
5
-// require all test files (files that ends with .spec.js)
6
-const testsContext = require.context('./specs', true, /\.spec$/);
7
-testsContext.keys().forEach(testsContext);
8
-
9
-// require all src files except main.js for coverage.
10
-// you can also change this to match only the subset of files that
11
-// you want coverage for.
12
-const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/);
13
-srcContext.keys().forEach(srcContext);

+ 0
- 33
test/unit/karma.conf.js View File

@@ -1,33 +0,0 @@
1
-// This is a karma config file. For more details see
2
-//   http://karma-runner.github.io/0.13/config/configuration-file.html
3
-// we are also using it with karma-webpack
4
-//   https://github.com/webpack/karma-webpack
5
-
6
-const webpackConfig = require('../../build/webpack.test.conf');
7
-
8
-module.exports = function (config) {
9
-    config.set({
10
-    // to run in additional browsers:
11
-    // 1. install corresponding karma launcher
12
-    //    http://karma-runner.github.io/0.13/config/browsers.html
13
-    // 2. add it to the `browsers` array below.
14
-        browsers: ['PhantomJS'],
15
-        frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'],
16
-        reporters: ['spec', 'coverage'],
17
-        files: ['./index.js'],
18
-        preprocessors: {
19
-            './index.js': ['webpack', 'sourcemap'],
20
-        },
21
-        webpack: webpackConfig,
22
-        webpackMiddleware: {
23
-            noInfo: true,
24
-        },
25
-        coverageReporter: {
26
-            dir: './coverage',
27
-            reporters: [
28
-        { type: 'lcov', subdir: '.' },
29
-        { type: 'text-summary' },
30
-            ],
31
-        },
32
-    });
33
-};

+ 0
- 11
test/unit/specs/Hello.spec.js View File

@@ -1,11 +0,0 @@
1
-import Vue from 'vue';
2
-import Hello from '@/components/Hello';
3
-
4
-describe('Hello.vue', () => {
5
-    it('should render correct contents', () => {
6
-        const Constructor = Vue.extend(Hello);
7
-        const vm = new Constructor().$mount();
8
-        expect(vm.$el.querySelector('.hello h1').textContent)
9
-      .to.equal('Welcome to Your Vue.js App');
10
-    });
11
-});