2
0
mirror of https://github.com/tenrok/vue-select.git synced 2026-06-22 10:30:34 +03:00

switch to vue cli for build

This commit is contained in:
Jeff
2020-12-23 20:21:02 -08:00
parent 1484366039
commit f80559ab89
50 changed files with 1975 additions and 1586 deletions
+3
View File
@@ -0,0 +1,3 @@
> 1%
last 2 versions
not dead
+25
View File
@@ -0,0 +1,25 @@
module.exports = {
root: true,
env: {
node: true
},
extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"],
parserOptions: {
parser: "babel-eslint"
},
rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off"
},
overrides: [
{
files: [
"**/__tests__/*.{j,t}s?(x)",
"**/tests/unit/**/*.spec.{j,t}s?(x)"
],
env: {
jest: true
}
}
]
};
+7 -11
View File
@@ -1,8 +1,12 @@
.DS_Store .DS_Store
node_modules node_modules
/dist
/tests/e2e/videos/
/tests/e2e/screenshots/
# local env files # local env files
.env
.env.local .env.local
.env.*.local .env.*.local
@@ -10,6 +14,7 @@ node_modules
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
pnpm-debug.log*
# Editor directories and files # Editor directories and files
.idea .idea
@@ -18,13 +23,4 @@ yarn-error.log*
*.ntvs* *.ntvs*
*.njsproj *.njsproj
*.sln *.sln
*.sw* *.sw?
# Project specific
coverage
dist
test/unit/coverage
package-lock.json
dev/dist
docs/.vuepress/dist
.netlify
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"]
};
+3
View File
@@ -0,0 +1,3 @@
{
"pluginsFile": "tests/e2e/plugins/index.js"
}
+1
View File
@@ -0,0 +1 @@
GITHUB_TOKEN=cc0a5db007fd27e736b9c2b23d2b626da44b4bbc
+56 -30
View File
@@ -1,39 +1,49 @@
{ {
"name": "vue-select", "name": "vue-select",
"version": "3.11.2", "version": "3.11.2",
"description": "Everything you wish the HTML <select> element could do, wrapped up into a lightweight, extensible Vue component.",
"author": "Jeff Sagal <sagalbot@gmail.com>",
"homepage": "https://vue-select.org",
"directories": {
"doc": "docs",
"test": "tests"
},
"private": false, "private": false,
"main": "dist/vue-select.js", "description": "Everything you wish the HTML <select> element could do, wrapped up into a lightweight, accessible and composable Vue component.",
"license": "MIT", "author": {
"prepare": "npm run build", "name": "Jeff Sagal",
"email": "sagalbot@gmail.com"
},
"scripts": { "scripts": {
"serve": "webpack-dev-server --config build/webpack.dev.conf.js --hot --progress -d", "serve": "vue-cli-service serve",
"serve:docs": "cd docs && yarn serve", "build": "vue-cli-service build",
"build": "cross-env NODE_ENV=production webpack --config build/webpack.prod.conf.js --progress", "test:unit": "vue-cli-service test:unit",
"test:e2e": "vue-cli-service test:e2e",
"lint": "vue-cli-service lint",
"build:docs": "cd docs && yarn build", "build:docs": "cd docs && yarn build",
"build:preview": "cd docs && yarn build", "build:preview": "cd docs && yarn build",
"test": "jest", "commit": "git-cz",
"semantic-release": "semantic-release", "semantic-release": "semantic-release",
"commit": "git-cz" "serve:docs": "cd docs && yarn serve",
"test": "jest"
}, },
"repository": { "main": "dist/vue-select.js",
"type": "git", "dependencies": {
"url": "https://github.com/sagalbot/vue-select.git" "core-js": "^3.6.5",
}, "vue": "^3.0.0"
"peerDependencies": {
"vue": "2.x"
},
"resolutions": {
"ajv": "6.8.1"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-e2e-cypress": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-unit-jest": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/test-utils": "^2.0.0-0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-vue": "^7.0.0-0",
"prettier": "^1.19.1",
"typescript": "~3.9.3",
"vue-jest": "^5.0.0-0"
},
"peerDependencies": {
"vue": "3.x"
}, },
"jest": { "jest": {
"moduleFileExtensions": [ "moduleFileExtensions": [
@@ -66,12 +76,11 @@
], ],
"coverageReporters": [ "coverageReporters": [
"text" "text"
] ],
"preset": "@vue/cli-plugin-unit-jest"
}, },
"config": { "bugs": {
"commitizen": { "url": "https://github.com/sagalbot/vue-select/issues"
"path": "./node_modules/cz-conventional-changelog"
}
}, },
"bundlewatch": { "bundlewatch": {
"files": [ "files": [
@@ -86,5 +95,22 @@
"maxSize": "6 KB" "maxSize": "6 KB"
} }
] ]
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
},
"directories": {
"doc": "docs",
"test": "tests"
},
"homepage": "https://vue-select.org",
"license": "MIT",
"prepare": "npm run build",
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/sagalbot/vue-select.git"
} }
} }
+5 -5
View File
@@ -1,8 +1,8 @@
module.exports = { module.exports = {
plugins: [ plugins: [
require('autoprefixer'), require("autoprefixer"),
require('cssnano')({ require("cssnano")({
preset: 'default', preset: "default"
}), })
], ]
}; };
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

+17
View File
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
+26
View File
@@ -0,0 +1,26 @@
<template>
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld msg="Welcome to Your Vue.js App" />
</template>
<script>
import HelloWorld from "./components/HelloWorld.vue";
export default {
name: "App",
components: {
HelloWorld
}
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

+3 -1
View File
@@ -1,5 +1,7 @@
<template> <template>
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10"> <svg xmlns="http://www.w3.org/2000/svg" width="10" height="10">
<path d="M6.895455 5l2.842897-2.842898c.348864-.348863.348864-.914488 0-1.263636L9.106534.261648c-.348864-.348864-.914489-.348864-1.263636 0L5 3.104545 2.157102.261648c-.348863-.348864-.914488-.348864-1.263636 0L.261648.893466c-.348864.348864-.348864.914489 0 1.263636L3.104545 5 .261648 7.842898c-.348864.348863-.348864.914488 0 1.263636l.631818.631818c.348864.348864.914773.348864 1.263636 0L5 6.895455l2.842898 2.842897c.348863.348864.914772.348864 1.263636 0l.631818-.631818c.348864-.348864.348864-.914489 0-1.263636L6.895455 5z"/> <path
d="M6.895455 5l2.842897-2.842898c.348864-.348863.348864-.914488 0-1.263636L9.106534.261648c-.348864-.348864-.914489-.348864-1.263636 0L5 3.104545 2.157102.261648c-.348863-.348864-.914488-.348864-1.263636 0L.261648.893466c-.348864.348864-.348864.914489 0 1.263636L3.104545 5 .261648 7.842898c-.348864.348863-.348864.914488 0 1.263636l.631818.631818c.348864.348864.914773.348864 1.263636 0L5 6.895455l2.842898 2.842897c.348863.348864.914772.348864 1.263636 0l.631818-.631818c.348864-.348864.348864-.914489 0-1.263636L6.895455 5z"
/>
</svg> </svg>
</template> </template>
+130
View File
@@ -0,0 +1,130 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br />
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener"
>vue-cli documentation</a
>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li>
<a
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel"
target="_blank"
rel="noopener"
>babel</a
>
</li>
<li>
<a
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint"
target="_blank"
rel="noopener"
>eslint</a
>
</li>
<li>
<a
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-unit-jest"
target="_blank"
rel="noopener"
>unit-jest</a
>
</li>
<li>
<a
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-e2e-cypress"
target="_blank"
rel="noopener"
>e2e-cypress</a
>
</li>
</ul>
<h3>Essential Links</h3>
<ul>
<li>
<a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a>
</li>
<li>
<a href="https://forum.vuejs.org" target="_blank" rel="noopener"
>Forum</a
>
</li>
<li>
<a href="https://chat.vuejs.org" target="_blank" rel="noopener"
>Community Chat</a
>
</li>
<li>
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener"
>Twitter</a
>
</li>
<li>
<a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a>
</li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li>
<a href="https://router.vuejs.org" target="_blank" rel="noopener"
>vue-router</a
>
</li>
<li>
<a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a>
</li>
<li>
<a
href="https://github.com/vuejs/vue-devtools#vue-devtools"
target="_blank"
rel="noopener"
>vue-devtools</a
>
</li>
<li>
<a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener"
>vue-loader</a
>
</li>
<li>
<a
href="https://github.com/vuejs/awesome-vue"
target="_blank"
rel="noopener"
>awesome-vue</a
>
</li>
</ul>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
+3 -1
View File
@@ -1,5 +1,7 @@
<template> <template>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="10"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="10">
<path d="M9.211364 7.59931l4.48338-4.867229c.407008-.441854.407008-1.158247 0-1.60046l-.73712-.80023c-.407008-.441854-1.066904-.441854-1.474243 0L7 5.198617 2.51662.33139c-.407008-.441853-1.066904-.441853-1.474243 0l-.737121.80023c-.407008.441854-.407008 1.158248 0 1.600461l4.48338 4.867228L7 10l2.211364-2.40069z"/> <path
d="M9.211364 7.59931l4.48338-4.867229c.407008-.441854.407008-1.158247 0-1.60046l-.73712-.80023c-.407008-.441854-1.066904-.441854-1.474243 0L7 5.198617 2.51662.33139c-.407008-.441853-1.066904-.441853-1.474243 0l-.737121.80023c-.407008.441854-.407008 1.158248 0 1.600461l4.48338 4.867228L7 10l2.211364-2.40069z"
/>
</svg> </svg>
</template> </template>
+1080 -1122
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -1,7 +1,7 @@
import Deselect from './Deselect'; import Deselect from "./Deselect";
import OpenIndicator from './OpenIndicator'; import OpenIndicator from "./OpenIndicator";
export default { export default {
Deselect, Deselect,
OpenIndicator OpenIndicator
} };
+30 -25
View File
@@ -1,27 +1,32 @@
export default { export default {
inserted (el, bindings, {context}) { inserted(el, bindings, { context }) {
if (context.appendToBody) { if (context.appendToBody) {
const {height, top, left, width} = context.$refs.toggle.getBoundingClientRect(); const {
let scrollX = window.scrollX || window.pageXOffset; height,
let scrollY = window.scrollY || window.pageYOffset; top,
el.unbindPosition = context.calculatePosition(el, context, { left,
width: width + 'px', width
left: (scrollX + left) + 'px', } = context.$refs.toggle.getBoundingClientRect();
top: (scrollY + top + height) + 'px', let scrollX = window.scrollX || window.pageXOffset;
}); let scrollY = window.scrollY || window.pageYOffset;
el.unbindPosition = context.calculatePosition(el, context, {
document.body.appendChild(el); width: width + "px",
} left: scrollX + left + "px",
}, top: scrollY + top + height + "px"
});
unbind (el, bindings, {context}) { document.body.appendChild(el);
if (context.appendToBody) { }
if (el.unbindPosition && typeof el.unbindPosition === 'function') { },
el.unbindPosition();
} unbind(el, bindings, { context }) {
if (el.parentNode) { if (context.appendToBody) {
el.parentNode.removeChild(el); if (el.unbindPosition && typeof el.unbindPosition === "function") {
} el.unbindPosition();
} }
}, if (el.parentNode) {
} el.parentNode.removeChild(el);
}
}
}
};
+4 -4
View File
@@ -1,5 +1,5 @@
import VueSelect from './components/Select.vue' import VueSelect from "./components/Select.vue";
import mixins from './mixins/index' import mixins from "./mixins/index";
export default VueSelect export default VueSelect;
export { VueSelect, mixins } export { VueSelect, mixins };
+4
View File
@@ -0,0 +1,4 @@
import { createApp } from "vue";
import App from "./App.vue";
createApp(App).mount("#app");
+11 -11
View File
@@ -7,13 +7,13 @@ export default {
*/ */
loading: { loading: {
type: Boolean, type: Boolean,
default: false, default: false
}, }
}, },
data () { data() {
return { return {
mutableLoading: false, mutableLoading: false
}; };
}, },
@@ -27,8 +27,8 @@ export default {
* *
* @emits search * @emits search
*/ */
search () { search() {
this.$emit('search', this.search, this.toggleLoading); this.$emit("search", this.search, this.toggleLoading);
}, },
/** /**
@@ -36,9 +36,9 @@ export default {
* mutable loading value. * mutable loading value.
* @param val * @param val
*/ */
loading (val) { loading(val) {
this.mutableLoading = val; this.mutableLoading = val;
}, }
}, },
methods: { methods: {
@@ -49,11 +49,11 @@ export default {
* @param toggle Boolean * @param toggle Boolean
* @returns {*} * @returns {*}
*/ */
toggleLoading (toggle = null) { toggleLoading(toggle = null) {
if (toggle == null) { if (toggle == null) {
return (this.mutableLoading = !this.mutableLoading); return (this.mutableLoading = !this.mutableLoading);
} }
return (this.mutableLoading = toggle); return (this.mutableLoading = toggle);
}, }
}, }
}; };
+4 -4
View File
@@ -1,5 +1,5 @@
import ajax from './ajax' import ajax from "./ajax";
import pointer from './typeAheadPointer' import pointer from "./typeAheadPointer";
import pointerScroll from './pointerScroll' import pointerScroll from "./pointerScroll";
export default { ajax, pointer, pointerScroll } export default { ajax, pointer, pointerScroll };
+1 -1
View File
@@ -11,7 +11,7 @@ export default {
if (this.autoscroll) { if (this.autoscroll) {
this.maybeAdjustScroll(); this.maybeAdjustScroll();
} }
}, }
}, },
methods: { methods: {
+7 -3
View File
@@ -2,7 +2,7 @@ export default {
data() { data() {
return { return {
typeAheadPointer: -1 typeAheadPointer: -1
} };
}, },
watch: { watch: {
@@ -37,7 +37,11 @@ export default {
* @return {void} * @return {void}
*/ */
typeAheadDown() { typeAheadDown() {
for (let i = this.typeAheadPointer + 1; i < this.filteredOptions.length; i++) { for (
let i = this.typeAheadPointer + 1;
i < this.filteredOptions.length;
i++
) {
if (this.selectable(this.filteredOptions[i])) { if (this.selectable(this.filteredOptions[i])) {
this.typeAheadPointer = i; this.typeAheadPointer = i;
break; break;
@@ -58,4 +62,4 @@ export default {
} }
} }
} }
} };
+5 -3
View File
@@ -5,9 +5,11 @@
function sortAndStringify(sortable) { function sortAndStringify(sortable) {
const ordered = {}; const ordered = {};
Object.keys(sortable).sort().forEach(key => { Object.keys(sortable)
ordered[key] = sortable[key]; .sort()
}); .forEach(key => {
ordered[key] = sortable[key];
});
return JSON.stringify(ordered); return JSON.stringify(ordered);
} }
+10
View File
@@ -0,0 +1,10 @@
module.exports = {
plugins: ["cypress"],
env: {
mocha: true,
"cypress/globals": true
},
rules: {
strict: "off"
}
};
+25
View File
@@ -0,0 +1,25 @@
/* eslint-disable arrow-body-style */
// https://docs.cypress.io/guides/guides/plugins-guide.html
// if you need a custom webpack configuration you can uncomment the following import
// and then use the `file:preprocessor` event
// as explained in the cypress docs
// https://docs.cypress.io/api/plugins/preprocessors-api.html#Examples
// /* eslint-disable import/no-extraneous-dependencies, global-require */
// const webpack = require('@cypress/webpack-preprocessor')
module.exports = (on, config) => {
// on('file:preprocessor', webpack({
// webpackOptions: require('@vue/cli-service/webpack.config'),
// watchOptions: {}
// }))
return Object.assign({}, config, {
fixturesFolder: "tests/e2e/fixtures",
integrationFolder: "tests/e2e/specs",
screenshotsFolder: "tests/e2e/screenshots",
videosFolder: "tests/e2e/videos",
supportFile: "tests/e2e/support/index.js"
});
};
+8
View File
@@ -0,0 +1,8 @@
// https://docs.cypress.io/api/introduction/api.html
describe("My First Test", () => {
it("Visits the app root url", () => {
cy.visit("/");
cy.contains("h1", "Welcome to Your Vue.js App");
});
});
+25
View File
@@ -0,0 +1,25 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
+20
View File
@@ -0,0 +1,20 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import "./commands";
// Alternatively you can use CommonJS syntax:
// require('./commands')
+12 -12
View File
@@ -1,6 +1,6 @@
import { shallowMount } from "@vue/test-utils"; import { shallowMount } from "@vue/test-utils";
import VueSelect from "../src/components/Select.vue"; import VueSelect from "../src/components/Select.vue";
import Vue from 'vue'; import Vue from "vue";
/** /**
* Trigger a submit event on the search * Trigger a submit event on the search
@@ -13,7 +13,7 @@ export const searchSubmit = (Wrapper, searchText = false) => {
if (searchText) { if (searchText) {
Wrapper.vm.search = searchText; Wrapper.vm.search = searchText;
} }
Wrapper.find({ ref: "search" }).trigger("keydown.enter") Wrapper.find({ ref: "search" }).trigger("keydown.enter");
}; };
/** /**
@@ -52,14 +52,13 @@ export const selectWithProps = (propsData = {}) => {
export const mountDefault = (props = {}, options = {}) => { export const mountDefault = (props = {}, options = {}) => {
return shallowMount(VueSelect, { return shallowMount(VueSelect, {
propsData: { propsData: {
options: ['one', 'two', 'three'], options: ["one", "two", "three"],
...props, ...props
}, },
...options, ...options
}); });
}; };
/** /**
* Returns a v-select component directly. * Returns a v-select component directly.
* @param props * @param props
@@ -68,11 +67,12 @@ export const mountDefault = (props = {}, options = {}) => {
*/ */
export const mountWithoutTestUtils = (props = {}, options = {}) => { export const mountWithoutTestUtils = (props = {}, options = {}) => {
return new Vue({ return new Vue({
render: createEl => createEl('vue-select', { render: createEl =>
ref: 'select', createEl("vue-select", {
props: {options: ['one', 'two', 'three'], ...props}, ref: "select",
...options props: { options: ["one", "two", "three"], ...props },
}), ...options
components: {VueSelect}, }),
components: { VueSelect }
}).$mount().$refs.select; }).$mount().$refs.select;
}; };
+2 -2
View File
@@ -3,6 +3,6 @@ module.exports = {
jest: true jest: true
}, },
rules: { rules: {
'import/no-extraneous-dependencies': 'off' "import/no-extraneous-dependencies": "off"
} }
} };
+7 -7
View File
@@ -1,6 +1,6 @@
import { selectWithProps } from "../helpers"; import { selectWithProps } from "../helpers";
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from "@vue/test-utils";
import vSelect from '../../src/components/Select'; import vSelect from "../../src/components/Select";
describe("Asynchronous Loading", () => { describe("Asynchronous Loading", () => {
it("can toggle the loading class", () => { it("can toggle the loading class", () => {
@@ -43,19 +43,19 @@ describe("Asynchronous Loading", () => {
const Select = shallowMount(vSelect, { const Select = shallowMount(vSelect, {
listeners: { listeners: {
search: (search, loading) => { search: (search, loading) => {
loading(false) loading(false);
}, }
}, }
}); });
Select.vm.mutableLoading = true; Select.vm.mutableLoading = true;
Select.vm.search = 'foo'; Select.vm.search = "foo";
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(Select.vm.mutableLoading).toEqual(false); expect(Select.vm.mutableLoading).toEqual(false);
}); });
it('will sync mutable loading with the loading prop', async () => { it("will sync mutable loading with the loading prop", async () => {
const Select = selectWithProps({ loading: false }); const Select = selectWithProps({ loading: false });
Select.setProps({ loading: true }); Select.setProps({ loading: true });
await Select.vm.$nextTick(); await Select.vm.$nextTick();
+15 -17
View File
@@ -1,30 +1,28 @@
import Vue from 'vue'; import Vue from "vue";
import { selectWithProps } from '../helpers'; import { selectWithProps } from "../helpers";
describe('Components API', () => { describe("Components API", () => {
it("swap the Deselect component", () => {
it('swap the Deselect component', () => { const Deselect = Vue.component("Deselect", {
const Deselect = Vue.component('Deselect', { render(createElement) {
render (createElement) { return createElement("button", "remove");
return createElement('button', 'remove'); }
},
}); });
const Select = selectWithProps({components: {Deselect}}); const Select = selectWithProps({ components: { Deselect } });
expect(Select.contains(Deselect)).toBeTruthy(); expect(Select.contains(Deselect)).toBeTruthy();
}); });
it('swap the OpenIndicator component', () => { it("swap the OpenIndicator component", () => {
const OpenIndicator = Vue.component('OpenIndicator', { const OpenIndicator = Vue.component("OpenIndicator", {
render (createElement) { render(createElement) {
return createElement('i', '^'); return createElement("i", "^");
}, }
}); });
const Select = selectWithProps({components: {OpenIndicator}}); const Select = selectWithProps({ components: { OpenIndicator } });
expect(Select.contains(OpenIndicator)).toBeTruthy(); expect(Select.contains(OpenIndicator)).toBeTruthy();
}); });
}); });
+12 -12
View File
@@ -1,9 +1,9 @@
import { mountDefault, selectWithProps } from '../helpers'; import { mountDefault, selectWithProps } from "../helpers";
describe("Removing values", () => { describe("Removing values", () => {
it("can remove the given tag when its close icon is clicked", async () => { it("can remove the given tag when its close icon is clicked", async () => {
const Select = selectWithProps({ multiple: true }); const Select = selectWithProps({ multiple: true });
Select.vm.$data._value = 'one'; Select.vm.$data._value = "one";
await Select.vm.$nextTick(); await Select.vm.$nextTick();
Select.find(".vs__deselect").trigger("click"); Select.find(".vs__deselect").trigger("click");
@@ -31,9 +31,9 @@ describe("Removing values", () => {
Select.vm.$data._value = ["one", "two"]; Select.vm.$data._value = ["one", "two"];
Select.find('.vs__search').trigger('keydown.backspace') Select.find(".vs__search").trigger("keydown.backspace");
expect(Select.emitted().input).toEqual([[['one']]]); expect(Select.emitted().input).toEqual([[["one"]]]);
expect(Select.vm.selectedValue).toEqual(["one"]); expect(Select.vm.selectedValue).toEqual(["one"]);
}); });
@@ -42,20 +42,20 @@ describe("Removing values", () => {
options: ["one", "two", "three"] options: ["one", "two", "three"]
}); });
Select.vm.$data._value = 'one'; Select.vm.$data._value = "one";
Select.vm.maybeDeleteValue(); Select.vm.maybeDeleteValue();
expect(Select.vm.selectedValue).toEqual([]); expect(Select.vm.selectedValue).toEqual([]);
}); });
it('will not emit input event if value has not changed with backspace', () => { it("will not emit input event if value has not changed with backspace", () => {
const Select = mountDefault(); const Select = mountDefault();
Select.vm.$data._value = 'one'; Select.vm.$data._value = "one";
Select.find({ ref: 'search' }).trigger('keydown.backspace'); Select.find({ ref: "search" }).trigger("keydown.backspace");
expect(Select.emitted().input.length).toBe(1); expect(Select.emitted().input.length).toBe(1);
Select.find({ ref: 'search' }).trigger('keydown.backspace'); Select.find({ ref: "search" }).trigger("keydown.backspace");
Select.find({ ref: 'search' }).trigger('keydown.backspace'); Select.find({ ref: "search" }).trigger("keydown.backspace");
expect(Select.emitted().input.length).toBe(1); expect(Select.emitted().input.length).toBe(1);
}); });
@@ -81,9 +81,9 @@ describe("Removing values", () => {
it("should remove selected value when clicked", () => { it("should remove selected value when clicked", () => {
const Select = selectWithProps({ const Select = selectWithProps({
options: ["foo", "bar"], options: ["foo", "bar"]
}); });
Select.vm.$data._value = 'foo'; Select.vm.$data._value = "foo";
expect(Select.vm.selectedValue).toEqual(["foo"]); expect(Select.vm.selectedValue).toEqual(["foo"]);
Select.find("button.vs__clear").trigger("click"); Select.find("button.vs__clear").trigger("click");
+18 -19
View File
@@ -1,10 +1,10 @@
import { selectWithProps } from "../helpers"; import { selectWithProps } from "../helpers";
import OpenIndicator from "../../src/components/OpenIndicator"; import OpenIndicator from "../../src/components/OpenIndicator";
const preventDefault = jest.fn() const preventDefault = jest.fn();
function clickEvent (currentTarget) { function clickEvent(currentTarget) {
return { currentTarget, preventDefault } return { currentTarget, preventDefault };
} }
describe("Toggling Dropdown", () => { describe("Toggling Dropdown", () => {
@@ -34,7 +34,7 @@ describe("Toggling Dropdown", () => {
Select.vm.toggleDropdown(clickEvent(Select.vm.$refs.search)); Select.vm.toggleDropdown(clickEvent(Select.vm.$refs.search));
expect(Select.vm.open).toEqual(true); expect(Select.vm.open).toEqual(true);
Select.vm.toggleDropdown(clickEvent(Select.vm.$el)); Select.vm.toggleDropdown(clickEvent(Select.vm.$el));
expect(Select.vm.open).toEqual(false) expect(Select.vm.open).toEqual(false);
}); });
it("should open the dropdown when the selected tag is clicked", () => { it("should open the dropdown when the selected tag is clicked", () => {
@@ -135,22 +135,22 @@ describe("Toggling Dropdown", () => {
}); });
Select.vm.search = "foo"; Select.vm.search = "foo";
Select.find('.vs__search').trigger('keydown.esc') Select.find(".vs__search").trigger("keydown.esc");
expect(Select.vm.search).toEqual(""); expect(Select.vm.search).toEqual("");
}); });
it("should have an open class when dropdown is active", () => { it("should have an open class when dropdown is active", () => {
const Select = selectWithProps(); const Select = selectWithProps();
expect(Select.vm.stateClasses['vs--open']).toEqual(false); expect(Select.vm.stateClasses["vs--open"]).toEqual(false);
Select.vm.open = true; Select.vm.open = true;
expect(Select.vm.stateClasses['vs--open']).toEqual(true); expect(Select.vm.stateClasses["vs--open"]).toEqual(true);
}); });
it("should not display the dropdown if noDrop is true", async () => { it("should not display the dropdown if noDrop is true", async () => {
const Select = selectWithProps({ const Select = selectWithProps({
noDrop: true, noDrop: true
}); });
Select.vm.toggleDropdown(clickEvent(Select.vm.$refs.search)); Select.vm.toggleDropdown(clickEvent(Select.vm.$refs.search));
@@ -158,34 +158,33 @@ describe("Toggling Dropdown", () => {
expect(Select.vm.open).toEqual(true); expect(Select.vm.open).toEqual(true);
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(Select.contains('.vs__dropdown-menu')).toBeFalsy(); expect(Select.contains(".vs__dropdown-menu")).toBeFalsy();
expect(Select.contains('.vs__dropdown-option')).toBeFalsy(); expect(Select.contains(".vs__dropdown-option")).toBeFalsy();
expect(Select.contains('.vs__no-options')).toBeFalsy(); expect(Select.contains(".vs__no-options")).toBeFalsy();
expect(Select.vm.stateClasses['vs--open']).toBeFalsy(); expect(Select.vm.stateClasses["vs--open"]).toBeFalsy();
}); });
it("should hide the open indicator if noDrop is true", () => { it("should hide the open indicator if noDrop is true", () => {
const Select = selectWithProps({ const Select = selectWithProps({
noDrop: true, noDrop: true
}); });
expect(Select.contains(OpenIndicator)).toBeFalsy(); expect(Select.contains(OpenIndicator)).toBeFalsy();
}); });
it("should not add the searchable state class when noDrop is true", () => { it("should not add the searchable state class when noDrop is true", () => {
const Select = selectWithProps({ const Select = selectWithProps({
noDrop: true, noDrop: true
}); });
expect(Select.classes('vs--searchable')).toBeFalsy(); expect(Select.classes("vs--searchable")).toBeFalsy();
}); });
it("should not add the searching state class when noDrop is true", () => { it("should not add the searching state class when noDrop is true", () => {
const Select = selectWithProps({ const Select = selectWithProps({
noDrop: true, noDrop: true
}); });
Select.vm.search = 'Canada'; Select.vm.search = "Canada";
expect(Select.classes('vs--searching')).toBeFalsy(); expect(Select.classes("vs--searching")).toBeFalsy();
}); });
}); });
+5 -5
View File
@@ -6,11 +6,11 @@ describe("Filtering Options", () => {
const Select = shallowMount(VueSelect, { const Select = shallowMount(VueSelect, {
propsData: { options: ["foo", "bar", "baz"] } propsData: { options: ["foo", "bar", "baz"] }
}); });
const input = Select.find('.vs__search'); const input = Select.find(".vs__search");
input.element.value = 'a' input.element.value = "a";
input.trigger('input') input.trigger("input");
expect(Select.vm.search).toEqual('a'); expect(Select.vm.search).toEqual("a");
}); });
it("should filter an array of strings", () => { it("should filter an array of strings", () => {
+27 -31
View File
@@ -1,74 +1,70 @@
import { mountDefault } from '../helpers'; import { mountDefault } from "../helpers";
describe('Custom Keydown Handlers', () => { describe("Custom Keydown Handlers", () => {
it("can use the map-keydown prop to trigger custom behaviour", () => {
it('can use the map-keydown prop to trigger custom behaviour', () => {
const onKeyDown = jest.fn(); const onKeyDown = jest.fn();
const Select = mountDefault({ const Select = mountDefault({
mapKeydown: (defaults, vm) => ({ ...defaults, 32: onKeyDown }), mapKeydown: (defaults, vm) => ({ ...defaults, 32: onKeyDown })
}); });
Select.find({ ref: 'search' }).trigger('keydown.space'); Select.find({ ref: "search" }).trigger("keydown.space");
expect(onKeyDown.mock.calls.length).toBe(1); expect(onKeyDown.mock.calls.length).toBe(1);
}); });
it('selectOnKeyCodes should trigger a selection for custom keycodes', () => { it("selectOnKeyCodes should trigger a selection for custom keycodes", () => {
const Select = mountDefault({ const Select = mountDefault({
selectOnKeyCodes: [32], selectOnKeyCodes: [32]
}); });
const spy = jest.spyOn(Select.vm, 'typeAheadSelect'); const spy = jest.spyOn(Select.vm, "typeAheadSelect");
Select.find({ ref: 'search' }).trigger('keydown.space'); Select.find({ ref: "search" }).trigger("keydown.space");
expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledTimes(1);
}); });
it('even works when combining selectOnKeyCodes with map-keydown', () => { it("even works when combining selectOnKeyCodes with map-keydown", () => {
const onKeyDown = jest.fn(); const onKeyDown = jest.fn();
const Select = mountDefault({ const Select = mountDefault({
mapKeydown: (defaults, vm) => ({ ...defaults, 32: onKeyDown }), mapKeydown: (defaults, vm) => ({ ...defaults, 32: onKeyDown }),
selectOnKeyCodes: [9], selectOnKeyCodes: [9]
}); });
const spy = jest.spyOn(Select.vm, 'typeAheadSelect'); const spy = jest.spyOn(Select.vm, "typeAheadSelect");
Select.find({ ref: 'search' }).trigger('keydown.space'); Select.find({ ref: "search" }).trigger("keydown.space");
expect(onKeyDown.mock.calls.length).toBe(1); expect(onKeyDown.mock.calls.length).toBe(1);
Select.find({ ref: 'search' }).trigger('keydown.tab'); Select.find({ ref: "search" }).trigger("keydown.tab");
expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledTimes(1);
}); });
describe('CompositionEvent support', () => { describe("CompositionEvent support", () => {
it("will not select a value with enter if the user is composing", () => {
it('will not select a value with enter if the user is composing', () => {
const Select = mountDefault(); const Select = mountDefault();
const spy = jest.spyOn(Select.vm, 'typeAheadSelect'); const spy = jest.spyOn(Select.vm, "typeAheadSelect");
Select.find({ ref: 'search' }).trigger('compositionstart'); Select.find({ ref: "search" }).trigger("compositionstart");
Select.find({ ref: 'search' }).trigger('keydown.enter'); Select.find({ ref: "search" }).trigger("keydown.enter");
expect(spy).toHaveBeenCalledTimes(0); expect(spy).toHaveBeenCalledTimes(0);
Select.find({ ref: 'search' }).trigger('compositionend'); Select.find({ ref: "search" }).trigger("compositionend");
Select.find({ ref: 'search' }).trigger('keydown.enter'); Select.find({ ref: "search" }).trigger("keydown.enter");
expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledTimes(1);
}); });
it('will not select a value with tab if the user is composing', () => { it("will not select a value with tab if the user is composing", () => {
const Select = mountDefault({ selectOnTab: true }); const Select = mountDefault({ selectOnTab: true });
const spy = jest.spyOn(Select.vm, 'typeAheadSelect'); const spy = jest.spyOn(Select.vm, "typeAheadSelect");
Select.find({ ref: 'search' }).trigger('compositionstart'); Select.find({ ref: "search" }).trigger("compositionstart");
Select.find({ ref: 'search' }).trigger('keydown.tab'); Select.find({ ref: "search" }).trigger("keydown.tab");
expect(spy).toHaveBeenCalledTimes(0); expect(spy).toHaveBeenCalledTimes(0);
Select.find({ ref: 'search' }).trigger('compositionend'); Select.find({ ref: "search" }).trigger("compositionend");
Select.find({ ref: 'search' }).trigger('keydown.tab'); Select.find({ ref: "search" }).trigger("keydown.tab");
expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledTimes(1);
}); });
}); });
}); });
+20 -16
View File
@@ -42,15 +42,19 @@ describe("Labels", () => {
expect(Select.vm.searchPlaceholder).not.toBeDefined(); expect(Select.vm.searchPlaceholder).not.toBeDefined();
}); });
describe('getOptionLabel', () => { describe("getOptionLabel", () => {
it('will return undefined if the option lacks the label key', () => { it("will return undefined if the option lacks the label key", () => {
const getOptionLabel = VueSelect.props.getOptionLabel.default.bind({ label: 'label' }); const getOptionLabel = VueSelect.props.getOptionLabel.default.bind({
expect(getOptionLabel({name: 'vue'})).toEqual(undefined); label: "label"
});
expect(getOptionLabel({ name: "vue" })).toEqual(undefined);
}); });
it('will return a string value for a valid key', () => { it("will return a string value for a valid key", () => {
const getOptionLabel = VueSelect.props.getOptionLabel.default.bind({ label: 'label' }); const getOptionLabel = VueSelect.props.getOptionLabel.default.bind({
expect(getOptionLabel({label: 'vue'})).toEqual('vue'); label: "label"
});
expect(getOptionLabel({ label: "vue" })).toEqual("vue");
}); });
/** /**
@@ -59,23 +63,23 @@ describe("Labels", () => {
* @see https://github.com/vuejs/vue/issues/10224 * @see https://github.com/vuejs/vue/issues/10224
* @see https://github.com/vuejs/vue/pull/10229 * @see https://github.com/vuejs/vue/pull/10229
*/ */
xit('will not call getOptionLabel if both scoped option slots are used and a filter is provided', () => { xit("will not call getOptionLabel if both scoped option slots are used and a filter is provided", () => {
const spy = spyOn(VueSelect.props.getOptionLabel, 'default'); const spy = spyOn(VueSelect.props.getOptionLabel, "default");
const Select = shallowMount(VueSelect, { const Select = shallowMount(VueSelect, {
propsData: { propsData: {
options: [{name: 'one'}], options: [{ name: "one" }],
filter: () => {}, filter: () => {}
}, },
scopedSlots: { scopedSlots: {
'option': '<span class="option">{{ props.name }}</span>', option: '<span class="option">{{ props.name }}</span>',
'selected-option': '<span class="selected">{{ props.name }}</span>', "selected-option": '<span class="selected">{{ props.name }}</span>'
}, }
}); });
Select.vm.select({name: 'one'}); Select.vm.select({ name: "one" });
expect(spy).toHaveBeenCalledTimes(0); expect(spy).toHaveBeenCalledTimes(0);
expect(Select.find('.selected').exists()).toBeTruthy(); expect(Select.find(".selected").exists()).toBeTruthy();
}); });
}); });
}); });
+17 -16
View File
@@ -1,31 +1,32 @@
import Select from '../../src/components/Select'; import Select from "../../src/components/Select";
describe('Comparing Options', () => {
describe("Comparing Options", () => {
const comparator = Select.methods.optionComparator.bind({ const comparator = Select.methods.optionComparator.bind({
getOptionKey: Select.props.getOptionKey.default, getOptionKey: Select.props.getOptionKey.default
}); });
it('can compare numbers', () => { it("can compare numbers", () => {
expect(comparator(1, 2)).toBeFalsy(); expect(comparator(1, 2)).toBeFalsy();
expect(comparator(1, 1)).toBeTruthy(); expect(comparator(1, 1)).toBeTruthy();
}); });
it('can compare strings', () => { it("can compare strings", () => {
expect(comparator('one', 'one')).toBeTruthy(); expect(comparator("one", "one")).toBeTruthy();
expect(comparator('one', 'two')).toBeFalsy(); expect(comparator("one", "two")).toBeFalsy();
}); });
it('can compare objects', () => { it("can compare objects", () => {
// compare ID keys // compare ID keys
expect(comparator({label: 'halo', id: 1}, {label: 'halo', id: 2})) expect(
.toBeFalsy(); comparator({ label: "halo", id: 1 }, { label: "halo", id: 2 })
).toBeFalsy();
// compare objects // compare objects
expect(comparator({label: 'halo', value: 1}, {label: 'halo', value: 1})) expect(
.toBeTruthy(); comparator({ label: "halo", value: 1 }, { label: "halo", value: 1 })
).toBeTruthy();
// compare objects with different orders // compare objects with different orders
expect(comparator({value: 1, label: 'halo'}, {label: 'halo', value: 1})) expect(
.toBeTruthy(); comparator({ value: 1, label: "halo" }, { label: "halo", value: 1 })
).toBeTruthy();
}); });
}); });
+13 -13
View File
@@ -1,25 +1,25 @@
import Select from '../../src/components/Select.vue'; import Select from "../../src/components/Select.vue";
describe('Serializing Option Keys', () => {
describe("Serializing Option Keys", () => {
const getOptionKey = Select.props.getOptionKey.default; const getOptionKey = Select.props.getOptionKey.default;
it('can serialize strings to a key', () => { it("can serialize strings to a key", () => {
expect(getOptionKey('vue')).toBe('vue'); expect(getOptionKey("vue")).toBe("vue");
}); });
it('can serialize integers to a key', () => { it("can serialize integers to a key", () => {
expect(getOptionKey(1)).toBe(1); expect(getOptionKey(1)).toBe(1);
}); });
it('can serialize objects to a key', () => { it("can serialize objects to a key", () => {
expect(getOptionKey({label: 'vue'})).toBe('{"label":"vue"}'); expect(getOptionKey({ label: "vue" })).toBe('{"label":"vue"}');
}); });
it('will use an ID property if the object contains one', () => { it("will use an ID property if the object contains one", () => {
expect(getOptionKey({id: 1})).toBe(1); expect(getOptionKey({ id: 1 })).toBe(1);
expect(getOptionKey({id: 'one'})).toBe('one'); expect(getOptionKey({ id: "one" })).toBe("one");
expect(getOptionKey({id: {im: 'a nested object'}})) expect(getOptionKey({ id: { im: "a nested object" } })).toEqual({
.toEqual({im: 'a nested object'}); im: "a nested object"
});
}); });
}); });
+82 -60
View File
@@ -1,6 +1,6 @@
import { mount, shallowMount } from '@vue/test-utils'; import { mount, shallowMount } from "@vue/test-utils";
import VueSelect from "../../src/components/Select"; import VueSelect from "../../src/components/Select";
import { mountDefault } from '../helpers'; import { mountDefault } from "../helpers";
describe("Reset on options change", () => { describe("Reset on options change", () => {
it("should not reset the selected value by default when the options property changes", () => { it("should not reset the selected value by default when the options property changes", () => {
@@ -8,80 +8,94 @@ describe("Reset on options change", () => {
propsData: { options: ["one"] } propsData: { options: ["one"] }
}); });
Select.vm.$data._value = 'one'; Select.vm.$data._value = "one";
Select.setProps({options: ["four", "five", "six"]}); Select.setProps({ options: ["four", "five", "six"] });
expect(Select.vm.selectedValue).toEqual(["one"]); expect(Select.vm.selectedValue).toEqual(["one"]);
}); });
describe('resetOnOptionsChange as a function', () => { describe("resetOnOptionsChange as a function", () => {
it('will yell at you if resetOnOptionsChange is not a function or boolean', () => { it("will yell at you if resetOnOptionsChange is not a function or boolean", () => {
const spy = jest.spyOn(console, 'error').mockImplementation(() => {}); const spy = jest.spyOn(console, "error").mockImplementation(() => {});
mountDefault({resetOnOptionsChange: 1}); mountDefault({ resetOnOptionsChange: 1 });
expect(spy.mock.calls[0][0]).toContain('Invalid prop: custom validator check failed for prop "resetOnOptionsChange"') expect(spy.mock.calls[0][0]).toContain(
'Invalid prop: custom validator check failed for prop "resetOnOptionsChange"'
mountDefault({resetOnOptionsChange: 'one'});
expect(spy.mock.calls[1][0]).toContain('Invalid prop: custom validator check failed for prop "resetOnOptionsChange"')
mountDefault({resetOnOptionsChange: []});
expect(spy.mock.calls[2][0]).toContain('Invalid prop: custom validator check failed for prop "resetOnOptionsChange"')
mountDefault({resetOnOptionsChange: {}});
expect(spy.mock.calls[3][0]).toContain('Invalid prop: custom validator check failed for prop "resetOnOptionsChange"')
});
it('should receive the new options, old options, and current value', async () => {
let resetOnOptionsChange = jest.fn(option => option);
const Select = mountDefault(
{resetOnOptionsChange, options: ['bear'], value: 'selected'},
); );
Select.setProps({options: ['lake', 'kite']}); mountDefault({ resetOnOptionsChange: "one" });
expect(spy.mock.calls[1][0]).toContain(
'Invalid prop: custom validator check failed for prop "resetOnOptionsChange"'
);
mountDefault({ resetOnOptionsChange: [] });
expect(spy.mock.calls[2][0]).toContain(
'Invalid prop: custom validator check failed for prop "resetOnOptionsChange"'
);
mountDefault({ resetOnOptionsChange: {} });
expect(spy.mock.calls[3][0]).toContain(
'Invalid prop: custom validator check failed for prop "resetOnOptionsChange"'
);
});
it("should receive the new options, old options, and current value", async () => {
let resetOnOptionsChange = jest.fn(option => option);
const Select = mountDefault({
resetOnOptionsChange,
options: ["bear"],
value: "selected"
});
Select.setProps({ options: ["lake", "kite"] });
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(resetOnOptionsChange).toHaveBeenCalledTimes(1); expect(resetOnOptionsChange).toHaveBeenCalledTimes(1);
expect(resetOnOptionsChange) expect(resetOnOptionsChange).toHaveBeenCalledWith(
.toHaveBeenCalledWith(['lake', 'kite'], ['bear'], ['selected']); ["lake", "kite"],
["bear"],
["selected"]
);
}); });
it('should allow resetOnOptionsChange to be a function that returns true', async () => { it("should allow resetOnOptionsChange to be a function that returns true", async () => {
let resetOnOptionsChange = () => true; let resetOnOptionsChange = () => true;
const Select = shallowMount(VueSelect, { const Select = shallowMount(VueSelect, {
propsData: {resetOnOptionsChange, options: ['one'], value: 'one'}, propsData: { resetOnOptionsChange, options: ["one"], value: "one" }
}); });
const spy = jest.spyOn(Select.vm, 'clearSelection'); const spy = jest.spyOn(Select.vm, "clearSelection");
Select.setProps({options: ['one', 'two']}); Select.setProps({ options: ["one", "two"] });
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledTimes(1);
}); });
it('should allow resetOnOptionsChange to be a function that returns false', () => { it("should allow resetOnOptionsChange to be a function that returns false", () => {
let resetOnOptionsChange = () => false; let resetOnOptionsChange = () => false;
const Select = shallowMount(VueSelect, { const Select = shallowMount(VueSelect, {
propsData: {resetOnOptionsChange, options: ['one'], value: 'one'}, propsData: { resetOnOptionsChange, options: ["one"], value: "one" }
}); });
const spy = jest.spyOn(Select.vm, 'clearSelection'); const spy = jest.spyOn(Select.vm, "clearSelection");
Select.setProps({options: ['one', 'two']}); Select.setProps({ options: ["one", "two"] });
expect(spy).not.toHaveBeenCalled(); expect(spy).not.toHaveBeenCalled();
}); });
it('should reset the options if the selectedValue does not exist in the new options', async () => { it("should reset the options if the selectedValue does not exist in the new options", async () => {
let resetOnOptionsChange = (options, old, val) => val.some(val => options.includes(val)); let resetOnOptionsChange = (options, old, val) =>
val.some(val => options.includes(val));
const Select = shallowMount(VueSelect, { const Select = shallowMount(VueSelect, {
propsData: {resetOnOptionsChange, options: ['one'], value: 'one'}, propsData: { resetOnOptionsChange, options: ["one"], value: "one" }
}); });
const spy = jest.spyOn(Select.vm, 'clearSelection'); const spy = jest.spyOn(Select.vm, "clearSelection");
Select.setProps({options: ['one', 'two']}); Select.setProps({ options: ["one", "two"] });
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(Select.vm.selectedValue).toEqual(['one']); expect(Select.vm.selectedValue).toEqual(["one"]);
Select.setProps({options: ['two']}); Select.setProps({ options: ["two"] });
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledTimes(1);
@@ -93,9 +107,9 @@ describe("Reset on options change", () => {
propsData: { resetOnOptionsChange: true, options: ["one"] } propsData: { resetOnOptionsChange: true, options: ["one"] }
}); });
Select.vm.$data._value = 'one'; Select.vm.$data._value = "one";
Select.setProps({options: ["four", "five", "six"]}); Select.setProps({ options: ["four", "five", "six"] });
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(Select.vm.selectedValue).toEqual([]); expect(Select.vm.selectedValue).toEqual([]);
@@ -103,39 +117,47 @@ describe("Reset on options change", () => {
it("should return correct selected value when the options property changes and a new option matches", async () => { it("should return correct selected value when the options property changes and a new option matches", async () => {
const Select = shallowMount(VueSelect, { const Select = shallowMount(VueSelect, {
propsData: { value: "one", options: [], reduce(option) { return option.value } } propsData: {
value: "one",
options: [],
reduce(option) {
return option.value;
}
}
}); });
Select.setProps({options: [{ label: "oneLabel", value: "one" }]}); Select.setProps({ options: [{ label: "oneLabel", value: "one" }] });
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(Select.vm.selectedValue).toEqual([{ label: "oneLabel", value: "one" }]); expect(Select.vm.selectedValue).toEqual([
{ label: "oneLabel", value: "one" }
]);
}); });
it('clearSearchOnBlur returns false when multiple is true', () => { it("clearSearchOnBlur returns false when multiple is true", () => {
const Select = mountDefault({}); const Select = mountDefault({});
let clearSearchOnBlur = jest.spyOn(Select.vm, 'clearSearchOnBlur'); let clearSearchOnBlur = jest.spyOn(Select.vm, "clearSearchOnBlur");
Select.find({ref: 'search'}).trigger('click'); Select.find({ ref: "search" }).trigger("click");
Select.setData({search: 'one'}); Select.setData({ search: "one" });
Select.find({ref: 'search'}).trigger('blur'); Select.find({ ref: "search" }).trigger("blur");
expect(clearSearchOnBlur).toHaveBeenCalledTimes(1); expect(clearSearchOnBlur).toHaveBeenCalledTimes(1);
expect(clearSearchOnBlur).toHaveBeenCalledWith({ expect(clearSearchOnBlur).toHaveBeenCalledWith({
clearSearchOnSelect: true, clearSearchOnSelect: true,
multiple: false, multiple: false
}); });
expect(Select.vm.search).toBe(''); expect(Select.vm.search).toBe("");
}); });
it('clearSearchOnBlur accepts a function', () => { it("clearSearchOnBlur accepts a function", () => {
let clearSearchOnBlur = jest.fn(() => false); let clearSearchOnBlur = jest.fn(() => false);
const Select = mountDefault({clearSearchOnBlur}); const Select = mountDefault({ clearSearchOnBlur });
Select.find({ref: 'search'}).trigger('click'); Select.find({ ref: "search" }).trigger("click");
Select.setData({search: 'one'}); Select.setData({ search: "one" });
Select.find({ref: 'search'}).trigger('blur'); Select.find({ ref: "search" }).trigger("blur");
expect(clearSearchOnBlur).toHaveBeenCalledTimes(1); expect(clearSearchOnBlur).toHaveBeenCalledTimes(1);
expect(Select.vm.search).toBe('one'); expect(Select.vm.search).toBe("one");
}); });
}); });
+55 -41
View File
@@ -10,7 +10,9 @@ describe("When reduce prop is defined", () => {
options: [{ label: "This is Foo", value: "foo" }] options: [{ label: "This is Foo", value: "foo" }]
} }
}); });
expect(Select.vm.selectedValue).toEqual([{ label: "This is Foo", value: "foo" }]); expect(Select.vm.selectedValue).toEqual([
{ label: "This is Foo", value: "foo" }
]);
}); });
it("can determine if an object is pre-selected", () => { it("can determine if an object is pre-selected", () => {
@@ -35,22 +37,24 @@ describe("When reduce prop is defined", () => {
).toEqual(true); ).toEqual(true);
}); });
it('can determine if an object is selected after its been chosen', () => { it("can determine if an object is selected after its been chosen", () => {
const Select = shallowMount(VueSelect, { const Select = shallowMount(VueSelect, {
propsData: { propsData: {
reduce: option => option.id, reduce: option => option.id,
options: [{id: 'foo', label: 'FooBar'}], options: [{ id: "foo", label: "FooBar" }]
}, }
});
Select.vm.select({id: 'foo', label: 'FooBar'});
expect(Select.vm.isOptionSelected({
id: 'foo',
label: 'This is FooBar',
})).toEqual(true);
}); });
Select.vm.select({ id: "foo", label: "FooBar" });
expect(
Select.vm.isOptionSelected({
id: "foo",
label: "This is FooBar"
})
).toEqual(true);
});
it("can accept an array of objects and pre-selected values (multiple)", () => { it("can accept an array of objects and pre-selected values (multiple)", () => {
const Select = shallowMount(VueSelect, { const Select = shallowMount(VueSelect, {
propsData: { propsData: {
@@ -64,7 +68,9 @@ describe("When reduce prop is defined", () => {
} }
}); });
expect(Select.vm.selectedValue).toEqual([{ label: "This is Foo", value: "foo" }]); expect(Select.vm.selectedValue).toEqual([
{ label: "This is Foo", value: "foo" }
]);
}); });
it("can deselect a pre-selected object", () => { it("can deselect a pre-selected object", () => {
@@ -79,7 +85,7 @@ describe("When reduce prop is defined", () => {
} }
}); });
Select.vm.$data._value = ['foo', 'bar']; Select.vm.$data._value = ["foo", "bar"];
Select.vm.deselect("foo"); Select.vm.deselect("foo");
expect(Select.vm.selectedValue).toEqual(["bar"]); expect(Select.vm.selectedValue).toEqual(["bar"]);
@@ -118,7 +124,7 @@ describe("When reduce prop is defined", () => {
return this.current; return this.current;
}, },
set(value) { set(value) {
if (value == 'baz') return; if (value == "baz") return;
this.current = value; this.current = value;
} }
} }
@@ -134,18 +140,24 @@ describe("When reduce prop is defined", () => {
const Select = Parent.vm.$children[0]; const Select = Parent.vm.$children[0];
expect(Select.value).toEqual("foo"); expect(Select.value).toEqual("foo");
expect(Select.selectedValue).toEqual([{ label: "This is Foo", value: "foo" }]); expect(Select.selectedValue).toEqual([
{ label: "This is Foo", value: "foo" }
]);
Select.select({ label: "This is Bar", value: "bar" }); Select.select({ label: "This is Bar", value: "bar" });
await Select.$nextTick(); await Select.$nextTick();
expect(Parent.vm.value).toEqual("bar"); expect(Parent.vm.value).toEqual("bar");
expect(Select.selectedValue).toEqual([{ label: "This is Bar", value: "bar" }]); expect(Select.selectedValue).toEqual([
{ label: "This is Bar", value: "bar" }
]);
// Parent denies to set baz // Parent denies to set baz
Select.select({ label: "This is Baz", value: "baz" }); Select.select({ label: "This is Baz", value: "baz" });
await Select.$nextTick(); await Select.$nextTick();
expect(Select.selectedValue).toEqual([{ label: "This is Bar", value: "bar" }]); expect(Select.selectedValue).toEqual([
expect(Parent.vm.value).toEqual('bar'); { label: "This is Bar", value: "bar" }
]);
expect(Parent.vm.value).toEqual("bar");
}); });
it("can generate labels using a custom label key", () => { it("can generate labels using a custom label key", () => {
@@ -155,7 +167,10 @@ describe("When reduce prop is defined", () => {
reduce: option => option.value, reduce: option => option.value,
value: ["CA"], value: ["CA"],
label: "name", label: "name",
options: [{ value: "CA", name: "Canada" }, { value: "US", name: "United States" }] options: [
{ value: "CA", name: "Canada" },
{ value: "US", name: "United States" }
]
} }
}); });
@@ -177,28 +192,28 @@ describe("When reduce prop is defined", () => {
); );
}); });
it('can work with falsey values', () => { it("can work with falsey values", () => {
const option = {value: 0, label: 'No'}; const option = { value: 0, label: "No" };
const Select = shallowMount(VueSelect, { const Select = shallowMount(VueSelect, {
propsData: { propsData: {
reduce: option => option.value, reduce: option => option.value,
options: [option, {value: 1, label: 'Yes'}], options: [option, { value: 1, label: "Yes" }],
value: 0, value: 0
}, }
}); });
expect(Select.vm.findOptionFromReducedValue(option)).toEqual(option); expect(Select.vm.findOptionFromReducedValue(option)).toEqual(option);
expect(Select.vm.selectedValue).toEqual([option]); expect(Select.vm.selectedValue).toEqual([option]);
}); });
it('works with null values', () => { it("works with null values", () => {
const option = {value: null, label: 'No'}; const option = { value: null, label: "No" };
const Select = shallowMount(VueSelect, { const Select = shallowMount(VueSelect, {
propsData: { propsData: {
reduce: option => option.value, reduce: option => option.value,
options: [option, {value: 1, label: 'Yes'}], options: [option, { value: 1, label: "Yes" }],
value: null, value: null
}, }
}); });
expect(Select.vm.findOptionFromReducedValue(option)).toEqual(option); expect(Select.vm.findOptionFromReducedValue(option)).toEqual(option);
@@ -233,7 +248,6 @@ describe("When reduce prop is defined", () => {
Select.vm.select(nestedOption); Select.vm.select(nestedOption);
expect(Select.vm.isOptionSelected(nestedOption)).toEqual(true); expect(Select.vm.isOptionSelected(nestedOption)).toEqual(true);
}); });
}); });
it("reacts correctly when value property changes", async () => { it("reacts correctly when value property changes", async () => {
@@ -252,10 +266,10 @@ describe("When reduce prop is defined", () => {
expect(Select.vm.selectedValue).toEqual([optionToChangeTo]); expect(Select.vm.selectedValue).toEqual([optionToChangeTo]);
}); });
describe('Reducing Tags', () => { describe("Reducing Tags", () => {
it('tracks values that have been created by the user', async () => { it("tracks values that have been created by the user", async () => {
const Parent = mount({ const Parent = mount({
data: () => ({selected: null, options: []}), data: () => ({ selected: null, options: [] }),
template: ` template: `
<v-select <v-select
v-model="selected" v-model="selected"
@@ -265,7 +279,7 @@ describe("When reduce prop is defined", () => {
:create-option="label => ({ label, value: -1 })" :create-option="label => ({ label, value: -1 })"
/> />
`, `,
components: {'v-select': VueSelect}, components: { "v-select": VueSelect }
}); });
const Select = Parent.vm.$children[0]; const Select = Parent.vm.$children[0];
@@ -273,15 +287,15 @@ describe("When reduce prop is defined", () => {
Select.$refs.search.focus(); Select.$refs.search.focus();
await Select.$nextTick(); await Select.$nextTick();
Select.search = 'hello'; Select.search = "hello";
await Select.$nextTick(); await Select.$nextTick();
Select.typeAheadSelect(); Select.typeAheadSelect();
await Select.$nextTick(); await Select.$nextTick();
// Then // Then
expect(Select.selectedValue).toEqual([{label: 'hello', value: -1}]); expect(Select.selectedValue).toEqual([{ label: "hello", value: -1 }]);
expect(Select.$refs.selectedOptions.textContent.trim()).toEqual('hello'); expect(Select.$refs.selectedOptions.textContent.trim()).toEqual("hello");
expect(Parent.vm.selected).toEqual(-1); expect(Parent.vm.selected).toEqual(-1);
}); });
}); });
+8 -8
View File
@@ -4,7 +4,7 @@ describe("Selectable prop", () => {
it("should select selectable option if clicked", async () => { it("should select selectable option if clicked", async () => {
const Select = selectWithProps({ const Select = selectWithProps({
options: ["one", "two", "three"], options: ["one", "two", "three"],
selectable: (option) => option === "one" selectable: option => option === "one"
}); });
Select.vm.$data.open = true; Select.vm.$data.open = true;
@@ -14,12 +14,12 @@ describe("Selectable prop", () => {
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(Select.vm.selectedValue).toEqual(["one"]); expect(Select.vm.selectedValue).toEqual(["one"]);
}) });
it("should not select not selectable option if clicked", async () => { it("should not select not selectable option if clicked", async () => {
const Select = selectWithProps({ const Select = selectWithProps({
options: ["one", "two", "three"], options: ["one", "two", "three"],
selectable: (option) => option === "one" selectable: option => option === "one"
}); });
Select.vm.$data.open = true; Select.vm.$data.open = true;
@@ -34,7 +34,7 @@ describe("Selectable prop", () => {
it("should skip non-selectable option on down arrow keyDown", () => { it("should skip non-selectable option on down arrow keyDown", () => {
const Select = selectWithProps({ const Select = selectWithProps({
options: ["one", "two", "three"], options: ["one", "two", "three"],
selectable: (option) => option !== "two" selectable: option => option !== "two"
}); });
Select.vm.typeAheadPointer = 1; Select.vm.typeAheadPointer = 1;
@@ -42,12 +42,12 @@ describe("Selectable prop", () => {
Select.find({ ref: "search" }).trigger("keydown.down"); Select.find({ ref: "search" }).trigger("keydown.down");
expect(Select.vm.typeAheadPointer).toEqual(2); expect(Select.vm.typeAheadPointer).toEqual(2);
}) });
it("should skip non-selectable option on up arrow keyDown", () => { it("should skip non-selectable option on up arrow keyDown", () => {
const Select = selectWithProps({ const Select = selectWithProps({
options: ["one", "two", "three"], options: ["one", "two", "three"],
selectable: (option) => option !== "two" selectable: option => option !== "two"
}); });
Select.vm.typeAheadPointer = 2; Select.vm.typeAheadPointer = 2;
@@ -55,5 +55,5 @@ describe("Selectable prop", () => {
Select.find({ ref: "search" }).trigger("keydown.up"); Select.find({ ref: "search" }).trigger("keydown.up");
expect(Select.vm.typeAheadPointer).toEqual(0); expect(Select.vm.typeAheadPointer).toEqual(0);
}) });
}) });
+30 -11
View File
@@ -1,6 +1,6 @@
import { mount, shallowMount } from "@vue/test-utils"; import { mount, shallowMount } from "@vue/test-utils";
import VueSelect from "../../src/components/Select.vue"; import VueSelect from "../../src/components/Select.vue";
import { mountDefault } from '../helpers'; import { mountDefault } from "../helpers";
describe("VS - Selecting Values", () => { describe("VS - Selecting Values", () => {
let defaultProps; let defaultProps;
@@ -81,7 +81,9 @@ describe("VS - Selecting Values", () => {
]; ];
Select.vm.deselect({ label: "This is Foo", value: "foo" }); Select.vm.deselect({ label: "This is Foo", value: "foo" });
expect(Select.vm.selectedValue).toEqual([{ label: "This is Bar", value: "bar" }]); expect(Select.vm.selectedValue).toEqual([
{ label: "This is Bar", value: "bar" }
]);
}); });
it("can deselect a pre-selected string", () => { it("can deselect a pre-selected string", () => {
@@ -193,15 +195,20 @@ describe("VS - Selecting Values", () => {
value: [{ label: "foo", value: "bar" }] value: [{ label: "foo", value: "bar" }]
} }
}); });
expect(Select.vm.isOptionSelected({ label: "foo", value: "bar" })).toEqual(true); expect(Select.vm.isOptionSelected({ label: "foo", value: "bar" })).toEqual(
true
);
}); });
it('can select two options with the same label', () => { it("can select two options with the same label", () => {
const options = [{label: 'one', id: 1}, {label: 'one', id: 2}]; const options = [
const Select = mountDefault({options, multiple: true}); { label: "one", id: 1 },
{ label: "one", id: 2 }
];
const Select = mountDefault({ options, multiple: true });
Select.vm.select({label: 'one', id: 1}); Select.vm.select({ label: "one", id: 1 });
Select.vm.select({label: 'one', id: 2}); Select.vm.select({ label: "one", id: 2 });
expect(Select.vm.selectedValue).toEqual(options); expect(Select.vm.selectedValue).toEqual(options);
}); });
@@ -223,7 +230,11 @@ describe("VS - Selecting Values", () => {
it("will not trigger the input event when multiple is true and selection is repeated", () => { it("will not trigger the input event when multiple is true and selection is repeated", () => {
const Select = shallowMount(VueSelect, { const Select = shallowMount(VueSelect, {
propsData: { multiple: true, value: ["foo ", "bar"], options: ["foo", "bar", "baz"] } propsData: {
multiple: true,
value: ["foo ", "bar"],
options: ["foo", "bar", "baz"]
}
}); });
Select.vm.select("bar"); Select.vm.select("bar");
@@ -257,7 +268,11 @@ describe("VS - Selecting Values", () => {
it("will trigger the option:selecting event regardless of current value when multiple is true", () => { it("will trigger the option:selecting event regardless of current value when multiple is true", () => {
const Select = shallowMount(VueSelect, { const Select = shallowMount(VueSelect, {
propsData: { multiple: true, value: ["foo", "bar"], options: ["foo", "bar"] } propsData: {
multiple: true,
value: ["foo", "bar"],
options: ["foo", "bar"]
}
}); });
Select.vm.select("bar"); Select.vm.select("bar");
Select.vm.select("bar"); Select.vm.select("bar");
@@ -293,7 +308,11 @@ describe("VS - Selecting Values", () => {
it("will trigger the option:selected event regardless of current value when multiple is true", () => { it("will trigger the option:selected event regardless of current value when multiple is true", () => {
const Select = shallowMount(VueSelect, { const Select = shallowMount(VueSelect, {
propsData: { multiple: true, value: ["foo", "bar"], options: ["foo", "bar"] } propsData: {
multiple: true,
value: ["foo", "bar"],
options: ["foo", "bar"]
}
}); });
Select.vm.deselect("bar"); Select.vm.deselect("bar");
Select.vm.deselect("bar"); Select.vm.deselect("bar");
+99 -68
View File
@@ -1,122 +1,153 @@
import { mountDefault } from '../helpers'; import { mountDefault } from "../helpers";
describe('Scoped Slots', () => { describe("Scoped Slots", () => {
it('receives an option object to the selected-option-container slot', () => { it("receives an option object to the selected-option-container slot", () => {
const Select = mountDefault( const Select = mountDefault(
{value: 'one'}, { value: "one" },
{ {
scopedSlots: { scopedSlots: {
'selected-option-container': `<span slot="selected-option-container" slot-scope="{option}">{{ option.label }}</span>`, "selected-option-container": `<span slot="selected-option-container" slot-scope="{option}">{{ option.label }}</span>`
}, }
}); }
);
expect(Select.find({ref: 'selectedOptions'}).text()).toEqual('one'); expect(Select.find({ ref: "selectedOptions" }).text()).toEqual("one");
}); });
describe('Slot: selected-option', () => { describe("Slot: selected-option", () => {
it('receives an option object to the selected-option slot', () => { it("receives an option object to the selected-option slot", () => {
const Select = mountDefault( const Select = mountDefault(
{value: 'one'}, { value: "one" },
{ {
scopedSlots: { scopedSlots: {
'selected-option': `<span slot="selected-option" slot-scope="option">{{ option.label }}</span>`, "selected-option": `<span slot="selected-option" slot-scope="option">{{ option.label }}</span>`
}, }
}); }
);
expect(Select.find('.vs__selected').text()).toEqual('one'); expect(Select.find(".vs__selected").text()).toEqual("one");
}); });
it('opens the dropdown when clicking an option in selected-option slot', it("opens the dropdown when clicking an option in selected-option slot", () => {
() => { const Select = mountDefault(
const Select = mountDefault( { value: "one" },
{value: 'one'}, {
{ scopedSlots: {
scopedSlots: { "selected-option": `<span class="my-option" slot-scope="option">{{ option.label }}</span>`
'selected-option': `<span class="my-option" slot-scope="option">{{ option.label }}</span>`, }
}, }
}); );
Select.find('.my-option').trigger('mousedown'); Select.find(".my-option").trigger("mousedown");
expect(Select.vm.open).toEqual(true); expect(Select.vm.open).toEqual(true);
}); });
}); });
it('receives an option object to the option slot in the dropdown menu', it("receives an option object to the option slot in the dropdown menu", async () => {
async () => { const Select = mountDefault(
const Select = mountDefault( { value: "one" },
{value: 'one'}, {
{ scopedSlots: {
scopedSlots: { option: `<span slot="option" slot-scope="option">{{ option.label }}</span>`
'option': `<span slot="option" slot-scope="option">{{ option.label }}</span>`, }
}, }
}); );
Select.vm.open = true; Select.vm.open = true;
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(Select.find({ref: 'dropdownMenu'}).text()).toEqual('onetwothree'); expect(Select.find({ ref: "dropdownMenu" }).text()).toEqual("onetwothree");
}); });
it('noOptions slot receives the current search text', async () => { it("noOptions slot receives the current search text", async () => {
const noOptions = jest.fn(); const noOptions = jest.fn();
const Select = mountDefault({}, { const Select = mountDefault(
scopedSlots: {'no-options': noOptions}, {},
}); {
scopedSlots: { "no-options": noOptions }
}
);
Select.vm.search = 'something not there'; Select.vm.search = "something not there";
Select.vm.open = true; Select.vm.open = true;
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(noOptions).toHaveBeenCalledWith({ expect(noOptions).toHaveBeenCalledWith({
loading: false, loading: false,
search: 'something not there', search: "something not there",
searching: true, searching: true
}) });
}); });
test('header slot props', async () => { test("header slot props", async () => {
const header = jest.fn(); const header = jest.fn();
const Select = mountDefault({}, { const Select = mountDefault(
scopedSlots: {header: header}, {},
}); {
scopedSlots: { header: header }
}
);
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(Object.keys(header.mock.calls[0][0])).toEqual([ expect(Object.keys(header.mock.calls[0][0])).toEqual([
'search', 'loading', 'searching', 'filteredOptions', 'deselect', "search",
"loading",
"searching",
"filteredOptions",
"deselect"
]); ]);
}); });
test('footer slot props', async () => { test("footer slot props", async () => {
const footer = jest.fn(); const footer = jest.fn();
const Select = mountDefault({}, { const Select = mountDefault(
scopedSlots: {footer: footer}, {},
}); {
scopedSlots: { footer: footer }
}
);
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(Object.keys(footer.mock.calls[0][0])).toEqual([ expect(Object.keys(footer.mock.calls[0][0])).toEqual([
'search', 'loading', 'searching', 'filteredOptions', 'deselect', "search",
"loading",
"searching",
"filteredOptions",
"deselect"
]); ]);
}); });
test('list-header slot props', async () => { test("list-header slot props", async () => {
const header = jest.fn(); const header = jest.fn();
const Select = mountDefault({}, { const Select = mountDefault(
scopedSlots: {'list-header': header}, {},
}); {
scopedSlots: { "list-header": header }
}
);
Select.vm.open = true; Select.vm.open = true;
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(Object.keys(header.mock.calls[0][0])).toEqual([ expect(Object.keys(header.mock.calls[0][0])).toEqual([
'search', 'loading', 'searching', 'filteredOptions', "search",
"loading",
"searching",
"filteredOptions"
]); ]);
}); });
test('list-footer slot props', async () => { test("list-footer slot props", async () => {
const footer = jest.fn(); const footer = jest.fn();
const Select = mountDefault({}, { const Select = mountDefault(
scopedSlots: {'list-footer': footer}, {},
}); {
scopedSlots: { "list-footer": footer }
}
);
Select.vm.open = true; Select.vm.open = true;
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(Object.keys(footer.mock.calls[0][0])).toEqual([ expect(Object.keys(footer.mock.calls[0][0])).toEqual([
'search', 'loading', 'searching', 'filteredOptions', "search",
"loading",
"searching",
"filteredOptions"
]); ]);
}); });
}); });
+11 -14
View File
@@ -2,12 +2,11 @@ import {
mountDefault, mountDefault,
searchSubmit, searchSubmit,
selectTag, selectTag,
selectWithProps, selectWithProps
} from '../helpers'; } from "../helpers";
import Select from '../../src/components/Select'; import Select from "../../src/components/Select";
describe("When Tagging Is Enabled", () => { describe("When Tagging Is Enabled", () => {
it("can determine if a given option string already exists", () => { it("can determine if a given option string already exists", () => {
const Select = selectWithProps({ taggable: true, options: ["one", "two"] }); const Select = selectWithProps({ taggable: true, options: ["one", "two"] });
expect(Select.vm.optionExists("one")).toEqual(true); expect(Select.vm.optionExists("one")).toEqual(true);
@@ -20,8 +19,8 @@ describe("When Tagging Is Enabled", () => {
options: [{ label: "one" }, { label: "two" }] options: [{ label: "one" }, { label: "two" }]
}); });
expect(Select.vm.optionExists({label: "one"})).toEqual(true); expect(Select.vm.optionExists({ label: "one" })).toEqual(true);
expect(Select.vm.optionExists({label: "three"})).toEqual(false); expect(Select.vm.optionExists({ label: "three" })).toEqual(false);
}); });
it("can determine if a given option object already exists when using custom labels", () => { it("can determine if a given option object already exists when using custom labels", () => {
@@ -31,7 +30,7 @@ describe("When Tagging Is Enabled", () => {
label: "foo" label: "foo"
}); });
const createOption = (text) => Select.vm.createOption(text); const createOption = text => Select.vm.createOption(text);
expect(Select.vm.optionExists(createOption("one"))).toEqual(true); expect(Select.vm.optionExists(createOption("one"))).toEqual(true);
expect(Select.vm.optionExists(createOption("three"))).toEqual(false); expect(Select.vm.optionExists(createOption("three"))).toEqual(false);
@@ -71,9 +70,7 @@ describe("When Tagging Is Enabled", () => {
await selectTag(Select, "two"); await selectTag(Select, "two");
expect(Select.vm.selectedValue).toEqual([ expect(Select.vm.selectedValue).toEqual([{ label: "two" }]);
{ label: "two" }
]);
}); });
it("should add a freshly created option/tag to the options list when pushTags is true", async () => { it("should add a freshly created option/tag to the options list when pushTags is true", async () => {
@@ -236,11 +233,11 @@ describe("When Tagging Is Enabled", () => {
multiple: true, multiple: true,
options: [{ label: "two" }] options: [{ label: "two" }]
}); });
const spy = jest.spyOn(Select.vm, 'select'); const spy = jest.spyOn(Select.vm, "select");
await selectTag(Select, "one"); await selectTag(Select, "one");
expect(Select.vm.selectedValue).toEqual([{ label: "one" }]); expect(Select.vm.selectedValue).toEqual([{ label: "one" }]);
expect(spy).lastCalledWith({label: 'one'}); expect(spy).lastCalledWith({ label: "one" });
expect(Select.vm.search).toEqual(""); expect(Select.vm.search).toEqual("");
await selectTag(Select, "one"); await selectTag(Select, "one");
@@ -258,6 +255,6 @@ describe("When Tagging Is Enabled", () => {
Select.find({ ref: "search" }).trigger("keydown.tab"); Select.find({ ref: "search" }).trigger("keydown.tab");
await Select.vm.$nextTick(); await Select.vm.$nextTick();
expect(Select.vm.selectedValue).toEqual(['one']); expect(Select.vm.selectedValue).toEqual(["one"]);
}) });
}); });
+12
View File
@@ -0,0 +1,12 @@
import { shallowMount } from "@vue/test-utils";
import HelloWorld from "@/components/HelloWorld.vue";
describe("HelloWorld.vue", () => {
it("renders props.msg when passed", () => {
const msg = "new message";
const wrapper = shallowMount(HelloWorld, {
props: { msg }
});
expect(wrapper.text()).toMatch(msg);
});
});
+9 -8
View File
@@ -1,14 +1,15 @@
import sortAndStringify from '../../../src/utility/sortAndStringify'; import sortAndStringify from "../../../src/utility/sortAndStringify";
test('it will stringify an object', () => { test("it will stringify an object", () => {
expect(sortAndStringify({hello: 'world'})).toEqual('{"hello":"world"}'); expect(sortAndStringify({ hello: "world" })).toEqual('{"hello":"world"}');
}); });
test('it will sort attributes alphabetically', () => { test("it will sort attributes alphabetically", () => {
expect(sortAndStringify({b: 'b', a: 'a'})).toEqual('{"a":"a","b":"b"}'); expect(sortAndStringify({ b: "b", a: "a" })).toEqual('{"a":"a","b":"b"}');
}); });
test('comparing two objects with unsorted keys', () => { test("comparing two objects with unsorted keys", () => {
expect(sortAndStringify({b: 'b', a: 'a'})) expect(sortAndStringify({ b: "b", a: "a" })).toEqual(
.toEqual(sortAndStringify({a: 'a', b: 'b'})) sortAndStringify({ a: "a", b: "b" })
);
}); });
+2 -2
View File
@@ -1,5 +1,5 @@
import uniqueId from '../../../src/utility/uniqueId'; import uniqueId from "../../../src/utility/uniqueId";
test('it generates a unique number', () => { test("it generates a unique number", () => {
expect(uniqueId()).not.toEqual(uniqueId()); expect(uniqueId()).not.toEqual(uniqueId());
}); });