2
0
mirror of https://github.com/tenrok/vue-select.git synced 2026-05-17 02:29:37 +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
node_modules
/dist
/tests/e2e/videos/
/tests/e2e/screenshots/
# local env files
.env
.env.local
.env.*.local
@@ -10,6 +14,7 @@ node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
@@ -18,13 +23,4 @@ yarn-error.log*
*.ntvs*
*.njsproj
*.sln
*.sw*
# Project specific
coverage
dist
test/unit/coverage
package-lock.json
dev/dist
docs/.vuepress/dist
.netlify
*.sw?
+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",
"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,
"main": "dist/vue-select.js",
"license": "MIT",
"prepare": "npm run build",
"description": "Everything you wish the HTML <select> element could do, wrapped up into a lightweight, accessible and composable Vue component.",
"author": {
"name": "Jeff Sagal",
"email": "sagalbot@gmail.com"
},
"scripts": {
"serve": "webpack-dev-server --config build/webpack.dev.conf.js --hot --progress -d",
"serve:docs": "cd docs && yarn serve",
"build": "cross-env NODE_ENV=production webpack --config build/webpack.prod.conf.js --progress",
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"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:preview": "cd docs && yarn build",
"test": "jest",
"commit": "git-cz",
"semantic-release": "semantic-release",
"commit": "git-cz"
"serve:docs": "cd docs && yarn serve",
"test": "jest"
},
"repository": {
"type": "git",
"url": "https://github.com/sagalbot/vue-select.git"
},
"peerDependencies": {
"vue": "2.x"
},
"resolutions": {
"ajv": "6.8.1"
"main": "dist/vue-select.js",
"dependencies": {
"core-js": "^3.6.5",
"vue": "^3.0.0"
},
"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": {
"moduleFileExtensions": [
@@ -66,12 +76,11 @@
],
"coverageReporters": [
"text"
]
],
"preset": "@vue/cli-plugin-unit-jest"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
"bugs": {
"url": "https://github.com/sagalbot/vue-select/issues"
},
"bundlewatch": {
"files": [
@@ -86,5 +95,22 @@
"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 = {
plugins: [
require('autoprefixer'),
require('cssnano')({
preset: 'default',
}),
],
require("autoprefixer"),
require("cssnano")({
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>
<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>
</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>
<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>
</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 OpenIndicator from './OpenIndicator';
import Deselect from "./Deselect";
import OpenIndicator from "./OpenIndicator";
export default {
Deselect,
OpenIndicator
}
};
+30 -25
View File
@@ -1,27 +1,32 @@
export default {
inserted (el, bindings, {context}) {
if (context.appendToBody) {
const {height, top, left, width} = context.$refs.toggle.getBoundingClientRect();
let scrollX = window.scrollX || window.pageXOffset;
let scrollY = window.scrollY || window.pageYOffset;
el.unbindPosition = context.calculatePosition(el, context, {
width: width + 'px',
left: (scrollX + left) + 'px',
top: (scrollY + top + height) + 'px',
});
document.body.appendChild(el);
}
},
inserted(el, bindings, { context }) {
if (context.appendToBody) {
const {
height,
top,
left,
width
} = context.$refs.toggle.getBoundingClientRect();
let scrollX = window.scrollX || window.pageXOffset;
let scrollY = window.scrollY || window.pageYOffset;
el.unbindPosition = context.calculatePosition(el, context, {
width: width + "px",
left: scrollX + left + "px",
top: scrollY + top + height + "px"
});
unbind (el, bindings, {context}) {
if (context.appendToBody) {
if (el.unbindPosition && typeof el.unbindPosition === 'function') {
el.unbindPosition();
}
if (el.parentNode) {
el.parentNode.removeChild(el);
}
}
},
}
document.body.appendChild(el);
}
},
unbind(el, bindings, { context }) {
if (context.appendToBody) {
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 mixins from './mixins/index'
import VueSelect from "./components/Select.vue";
import mixins from "./mixins/index";
export default VueSelect
export { VueSelect, mixins }
export default VueSelect;
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: {
type: Boolean,
default: false,
},
default: false
}
},
data () {
data() {
return {
mutableLoading: false,
mutableLoading: false
};
},
@@ -27,8 +27,8 @@ export default {
*
* @emits search
*/
search () {
this.$emit('search', this.search, this.toggleLoading);
search() {
this.$emit("search", this.search, this.toggleLoading);
},
/**
@@ -36,9 +36,9 @@ export default {
* mutable loading value.
* @param val
*/
loading (val) {
loading(val) {
this.mutableLoading = val;
},
}
},
methods: {
@@ -49,11 +49,11 @@ export default {
* @param toggle Boolean
* @returns {*}
*/
toggleLoading (toggle = null) {
toggleLoading(toggle = null) {
if (toggle == null) {
return (this.mutableLoading = !this.mutableLoading);
}
return (this.mutableLoading = toggle);
},
},
}
}
};
+4 -4
View File
@@ -1,5 +1,5 @@
import ajax from './ajax'
import pointer from './typeAheadPointer'
import pointerScroll from './pointerScroll'
import ajax from "./ajax";
import pointer from "./typeAheadPointer";
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) {
this.maybeAdjustScroll();
}
},
}
},
methods: {
+7 -3
View File
@@ -2,7 +2,7 @@ export default {
data() {
return {
typeAheadPointer: -1
}
};
},
watch: {
@@ -37,7 +37,11 @@ export default {
* @return {void}
*/
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])) {
this.typeAheadPointer = i;
break;
@@ -58,4 +62,4 @@ export default {
}
}
}
}
};
+5 -3
View File
@@ -5,9 +5,11 @@
function sortAndStringify(sortable) {
const ordered = {};
Object.keys(sortable).sort().forEach(key => {
ordered[key] = sortable[key];
});
Object.keys(sortable)
.sort()
.forEach(key => {
ordered[key] = sortable[key];
});
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 VueSelect from "../src/components/Select.vue";
import Vue from 'vue';
import Vue from "vue";
/**
* Trigger a submit event on the search
@@ -13,7 +13,7 @@ export const searchSubmit = (Wrapper, searchText = false) => {
if (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 = {}) => {
return shallowMount(VueSelect, {
propsData: {
options: ['one', 'two', 'three'],
...props,
options: ["one", "two", "three"],
...props
},
...options,
...options
});
};
/**
* Returns a v-select component directly.
* @param props
@@ -68,11 +67,12 @@ export const mountDefault = (props = {}, options = {}) => {
*/
export const mountWithoutTestUtils = (props = {}, options = {}) => {
return new Vue({
render: createEl => createEl('vue-select', {
ref: 'select',
props: {options: ['one', 'two', 'three'], ...props},
...options
}),
components: {VueSelect},
render: createEl =>
createEl("vue-select", {
ref: "select",
props: { options: ["one", "two", "three"], ...props },
...options
}),
components: { VueSelect }
}).$mount().$refs.select;
};
+2 -2
View File
@@ -3,6 +3,6 @@ module.exports = {
jest: true
},
rules: {
'import/no-extraneous-dependencies': 'off'
"import/no-extraneous-dependencies": "off"
}
}
};
+7 -7
View File
@@ -1,6 +1,6 @@
import { selectWithProps } from "../helpers";
import { shallowMount } from '@vue/test-utils';
import vSelect from '../../src/components/Select';
import { shallowMount } from "@vue/test-utils";
import vSelect from "../../src/components/Select";
describe("Asynchronous Loading", () => {
it("can toggle the loading class", () => {
@@ -43,19 +43,19 @@ describe("Asynchronous Loading", () => {
const Select = shallowMount(vSelect, {
listeners: {
search: (search, loading) => {
loading(false)
},
},
loading(false);
}
}
});
Select.vm.mutableLoading = true;
Select.vm.search = 'foo';
Select.vm.search = "foo";
await Select.vm.$nextTick();
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 });
Select.setProps({ loading: true });
await Select.vm.$nextTick();
+15 -17
View File
@@ -1,30 +1,28 @@
import Vue from 'vue';
import { selectWithProps } from '../helpers';
import Vue from "vue";
import { selectWithProps } from "../helpers";
describe('Components API', () => {
it('swap the Deselect component', () => {
const Deselect = Vue.component('Deselect', {
render (createElement) {
return createElement('button', 'remove');
},
describe("Components API", () => {
it("swap the Deselect component", () => {
const Deselect = Vue.component("Deselect", {
render(createElement) {
return createElement("button", "remove");
}
});
const Select = selectWithProps({components: {Deselect}});
const Select = selectWithProps({ components: { Deselect } });
expect(Select.contains(Deselect)).toBeTruthy();
});
it('swap the OpenIndicator component', () => {
const OpenIndicator = Vue.component('OpenIndicator', {
render (createElement) {
return createElement('i', '^');
},
it("swap the OpenIndicator component", () => {
const OpenIndicator = Vue.component("OpenIndicator", {
render(createElement) {
return createElement("i", "^");
}
});
const Select = selectWithProps({components: {OpenIndicator}});
const Select = selectWithProps({ components: { OpenIndicator } });
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", () => {
it("can remove the given tag when its close icon is clicked", async () => {
const Select = selectWithProps({ multiple: true });
Select.vm.$data._value = 'one';
Select.vm.$data._value = "one";
await Select.vm.$nextTick();
Select.find(".vs__deselect").trigger("click");
@@ -31,9 +31,9 @@ describe("Removing values", () => {
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"]);
});
@@ -42,20 +42,20 @@ describe("Removing values", () => {
options: ["one", "two", "three"]
});
Select.vm.$data._value = 'one';
Select.vm.$data._value = "one";
Select.vm.maybeDeleteValue();
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();
Select.vm.$data._value = 'one';
Select.find({ ref: 'search' }).trigger('keydown.backspace');
Select.vm.$data._value = "one";
Select.find({ ref: "search" }).trigger("keydown.backspace");
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);
});
@@ -81,9 +81,9 @@ describe("Removing values", () => {
it("should remove selected value when clicked", () => {
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"]);
Select.find("button.vs__clear").trigger("click");
+18 -19
View File
@@ -1,10 +1,10 @@
import { selectWithProps } from "../helpers";
import OpenIndicator from "../../src/components/OpenIndicator";
const preventDefault = jest.fn()
const preventDefault = jest.fn();
function clickEvent (currentTarget) {
return { currentTarget, preventDefault }
function clickEvent(currentTarget) {
return { currentTarget, preventDefault };
}
describe("Toggling Dropdown", () => {
@@ -34,7 +34,7 @@ describe("Toggling Dropdown", () => {
Select.vm.toggleDropdown(clickEvent(Select.vm.$refs.search));
expect(Select.vm.open).toEqual(true);
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", () => {
@@ -135,22 +135,22 @@ describe("Toggling Dropdown", () => {
});
Select.vm.search = "foo";
Select.find('.vs__search').trigger('keydown.esc')
Select.find(".vs__search").trigger("keydown.esc");
expect(Select.vm.search).toEqual("");
});
it("should have an open class when dropdown is active", () => {
const Select = selectWithProps();
expect(Select.vm.stateClasses['vs--open']).toEqual(false);
expect(Select.vm.stateClasses["vs--open"]).toEqual(false);
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 () => {
const Select = selectWithProps({
noDrop: true,
noDrop: true
});
Select.vm.toggleDropdown(clickEvent(Select.vm.$refs.search));
@@ -158,34 +158,33 @@ describe("Toggling Dropdown", () => {
expect(Select.vm.open).toEqual(true);
await Select.vm.$nextTick();
expect(Select.contains('.vs__dropdown-menu')).toBeFalsy();
expect(Select.contains('.vs__dropdown-option')).toBeFalsy();
expect(Select.contains('.vs__no-options')).toBeFalsy();
expect(Select.vm.stateClasses['vs--open']).toBeFalsy();
expect(Select.contains(".vs__dropdown-menu")).toBeFalsy();
expect(Select.contains(".vs__dropdown-option")).toBeFalsy();
expect(Select.contains(".vs__no-options")).toBeFalsy();
expect(Select.vm.stateClasses["vs--open"]).toBeFalsy();
});
it("should hide the open indicator if noDrop is true", () => {
const Select = selectWithProps({
noDrop: true,
noDrop: true
});
expect(Select.contains(OpenIndicator)).toBeFalsy();
});
it("should not add the searchable state class when noDrop is true", () => {
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", () => {
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, {
propsData: { options: ["foo", "bar", "baz"] }
});
const input = Select.find('.vs__search');
input.element.value = 'a'
input.trigger('input')
expect(Select.vm.search).toEqual('a');
const input = Select.find(".vs__search");
input.element.value = "a";
input.trigger("input");
expect(Select.vm.search).toEqual("a");
});
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', () => {
it('can use the map-keydown prop to trigger custom behaviour', () => {
describe("Custom Keydown Handlers", () => {
it("can use the map-keydown prop to trigger custom behaviour", () => {
const onKeyDown = jest.fn();
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);
});
it('selectOnKeyCodes should trigger a selection for custom keycodes', () => {
it("selectOnKeyCodes should trigger a selection for custom keycodes", () => {
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);
});
it('even works when combining selectOnKeyCodes with map-keydown', () => {
it("even works when combining selectOnKeyCodes with map-keydown", () => {
const onKeyDown = jest.fn();
const Select = mountDefault({
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);
Select.find({ ref: 'search' }).trigger('keydown.tab');
Select.find({ ref: "search" }).trigger("keydown.tab");
expect(spy).toHaveBeenCalledTimes(1);
});
describe('CompositionEvent support', () => {
it('will not select a value with enter if the user is composing', () => {
describe("CompositionEvent support", () => {
it("will not select a value with enter if the user is composing", () => {
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('keydown.enter');
Select.find({ ref: "search" }).trigger("compositionstart");
Select.find({ ref: "search" }).trigger("keydown.enter");
expect(spy).toHaveBeenCalledTimes(0);
Select.find({ ref: 'search' }).trigger('compositionend');
Select.find({ ref: 'search' }).trigger('keydown.enter');
Select.find({ ref: "search" }).trigger("compositionend");
Select.find({ ref: "search" }).trigger("keydown.enter");
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 spy = jest.spyOn(Select.vm, 'typeAheadSelect');
const spy = jest.spyOn(Select.vm, "typeAheadSelect");
Select.find({ ref: 'search' }).trigger('compositionstart');
Select.find({ ref: 'search' }).trigger('keydown.tab');
Select.find({ ref: "search" }).trigger("compositionstart");
Select.find({ ref: "search" }).trigger("keydown.tab");
expect(spy).toHaveBeenCalledTimes(0);
Select.find({ ref: 'search' }).trigger('compositionend');
Select.find({ ref: 'search' }).trigger('keydown.tab');
Select.find({ ref: "search" }).trigger("compositionend");
Select.find({ ref: "search" }).trigger("keydown.tab");
expect(spy).toHaveBeenCalledTimes(1);
});
});
});
+20 -16
View File
@@ -42,15 +42,19 @@ describe("Labels", () => {
expect(Select.vm.searchPlaceholder).not.toBeDefined();
});
describe('getOptionLabel', () => {
it('will return undefined if the option lacks the label key', () => {
const getOptionLabel = VueSelect.props.getOptionLabel.default.bind({ label: 'label' });
expect(getOptionLabel({name: 'vue'})).toEqual(undefined);
describe("getOptionLabel", () => {
it("will return undefined if the option lacks the label key", () => {
const getOptionLabel = VueSelect.props.getOptionLabel.default.bind({
label: "label"
});
expect(getOptionLabel({ name: "vue" })).toEqual(undefined);
});
it('will return a string value for a valid key', () => {
const getOptionLabel = VueSelect.props.getOptionLabel.default.bind({ label: 'label' });
expect(getOptionLabel({label: 'vue'})).toEqual('vue');
it("will return a string value for a valid key", () => {
const getOptionLabel = VueSelect.props.getOptionLabel.default.bind({
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/pull/10229
*/
xit('will not call getOptionLabel if both scoped option slots are used and a filter is provided', () => {
const spy = spyOn(VueSelect.props.getOptionLabel, 'default');
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 Select = shallowMount(VueSelect, {
propsData: {
options: [{name: 'one'}],
filter: () => {},
options: [{ name: "one" }],
filter: () => {}
},
scopedSlots: {
'option': '<span class="option">{{ props.name }}</span>',
'selected-option': '<span class="selected">{{ props.name }}</span>',
},
option: '<span class="option">{{ 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(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';
describe('Comparing Options', () => {
import Select from "../../src/components/Select";
describe("Comparing Options", () => {
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, 1)).toBeTruthy();
});
it('can compare strings', () => {
expect(comparator('one', 'one')).toBeTruthy();
expect(comparator('one', 'two')).toBeFalsy();
it("can compare strings", () => {
expect(comparator("one", "one")).toBeTruthy();
expect(comparator("one", "two")).toBeFalsy();
});
it('can compare objects', () => {
it("can compare objects", () => {
// compare ID keys
expect(comparator({label: 'halo', id: 1}, {label: 'halo', id: 2}))
.toBeFalsy();
expect(
comparator({ label: "halo", id: 1 }, { label: "halo", id: 2 })
).toBeFalsy();
// compare objects
expect(comparator({label: 'halo', value: 1}, {label: 'halo', value: 1}))
.toBeTruthy();
expect(
comparator({ label: "halo", value: 1 }, { label: "halo", value: 1 })
).toBeTruthy();
// compare objects with different orders
expect(comparator({value: 1, label: 'halo'}, {label: 'halo', value: 1}))
.toBeTruthy();
expect(
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';
describe('Serializing Option Keys', () => {
import Select from "../../src/components/Select.vue";
describe("Serializing Option Keys", () => {
const getOptionKey = Select.props.getOptionKey.default;
it('can serialize strings to a key', () => {
expect(getOptionKey('vue')).toBe('vue');
it("can serialize strings to a key", () => {
expect(getOptionKey("vue")).toBe("vue");
});
it('can serialize integers to a key', () => {
it("can serialize integers to a key", () => {
expect(getOptionKey(1)).toBe(1);
});
it('can serialize objects to a key', () => {
expect(getOptionKey({label: 'vue'})).toBe('{"label":"vue"}');
it("can serialize objects to a key", () => {
expect(getOptionKey({ label: "vue" })).toBe('{"label":"vue"}');
});
it('will use an ID property if the object contains one', () => {
expect(getOptionKey({id: 1})).toBe(1);
expect(getOptionKey({id: 'one'})).toBe('one');
expect(getOptionKey({id: {im: 'a nested object'}}))
.toEqual({im: 'a nested object'});
it("will use an ID property if the object contains one", () => {
expect(getOptionKey({ id: 1 })).toBe(1);
expect(getOptionKey({ id: "one" })).toBe("one");
expect(getOptionKey({ id: { im: "a nested object" } })).toEqual({
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 { mountDefault } from '../helpers';
import { mountDefault } from "../helpers";
describe("Reset on options change", () => {
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"] }
});
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"]);
});
describe('resetOnOptionsChange as a function', () => {
it('will yell at you if resetOnOptionsChange is not a function or boolean', () => {
const spy = jest.spyOn(console, 'error').mockImplementation(() => {});
describe("resetOnOptionsChange as a function", () => {
it("will yell at you if resetOnOptionsChange is not a function or boolean", () => {
const spy = jest.spyOn(console, "error").mockImplementation(() => {});
mountDefault({resetOnOptionsChange: 1});
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'},
mountDefault({ resetOnOptionsChange: 1 });
expect(spy.mock.calls[0][0]).toContain(
'Invalid prop: custom validator check failed for prop "resetOnOptionsChange"'
);
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();
expect(resetOnOptionsChange).toHaveBeenCalledTimes(1);
expect(resetOnOptionsChange)
.toHaveBeenCalledWith(['lake', 'kite'], ['bear'], ['selected']);
expect(resetOnOptionsChange).toHaveBeenCalledWith(
["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;
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();
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;
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();
});
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));
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));
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();
expect(Select.vm.selectedValue).toEqual(['one']);
expect(Select.vm.selectedValue).toEqual(["one"]);
Select.setProps({options: ['two']});
Select.setProps({ options: ["two"] });
await Select.vm.$nextTick();
expect(spy).toHaveBeenCalledTimes(1);
@@ -93,9 +107,9 @@ describe("Reset on options change", () => {
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();
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 () => {
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();
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({});
let clearSearchOnBlur = jest.spyOn(Select.vm, 'clearSearchOnBlur');
Select.find({ref: 'search'}).trigger('click');
Select.setData({search: 'one'});
Select.find({ref: 'search'}).trigger('blur');
let clearSearchOnBlur = jest.spyOn(Select.vm, "clearSearchOnBlur");
Select.find({ ref: "search" }).trigger("click");
Select.setData({ search: "one" });
Select.find({ ref: "search" }).trigger("blur");
expect(clearSearchOnBlur).toHaveBeenCalledTimes(1);
expect(clearSearchOnBlur).toHaveBeenCalledWith({
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);
const Select = mountDefault({clearSearchOnBlur});
const Select = mountDefault({ clearSearchOnBlur });
Select.find({ref: 'search'}).trigger('click');
Select.setData({search: 'one'});
Select.find({ref: 'search'}).trigger('blur');
Select.find({ ref: "search" }).trigger("click");
Select.setData({ search: "one" });
Select.find({ ref: "search" }).trigger("blur");
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" }]
}
});
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", () => {
@@ -35,22 +37,24 @@ describe("When reduce prop is defined", () => {
).toEqual(true);
});
it('can determine if an object is selected after its been chosen', () => {
const Select = shallowMount(VueSelect, {
propsData: {
reduce: option => option.id,
options: [{id: 'foo', label: 'FooBar'}],
},
});
Select.vm.select({id: 'foo', label: 'FooBar'});
expect(Select.vm.isOptionSelected({
id: 'foo',
label: 'This is FooBar',
})).toEqual(true);
it("can determine if an object is selected after its been chosen", () => {
const Select = shallowMount(VueSelect, {
propsData: {
reduce: option => option.id,
options: [{ id: "foo", label: "FooBar" }]
}
});
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)", () => {
const Select = shallowMount(VueSelect, {
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", () => {
@@ -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");
expect(Select.vm.selectedValue).toEqual(["bar"]);
@@ -118,7 +124,7 @@ describe("When reduce prop is defined", () => {
return this.current;
},
set(value) {
if (value == 'baz') return;
if (value == "baz") return;
this.current = value;
}
}
@@ -134,18 +140,24 @@ describe("When reduce prop is defined", () => {
const Select = Parent.vm.$children[0];
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" });
await Select.$nextTick();
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
Select.select({ label: "This is Baz", value: "baz" });
await Select.$nextTick();
expect(Select.selectedValue).toEqual([{ label: "This is Bar", value: "bar" }]);
expect(Parent.vm.value).toEqual('bar');
expect(Select.selectedValue).toEqual([
{ label: "This is Bar", value: "bar" }
]);
expect(Parent.vm.value).toEqual("bar");
});
it("can generate labels using a custom label key", () => {
@@ -155,7 +167,10 @@ describe("When reduce prop is defined", () => {
reduce: option => option.value,
value: ["CA"],
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', () => {
const option = {value: 0, label: 'No'};
it("can work with falsey values", () => {
const option = { value: 0, label: "No" };
const Select = shallowMount(VueSelect, {
propsData: {
reduce: option => option.value,
options: [option, {value: 1, label: 'Yes'}],
value: 0,
},
options: [option, { value: 1, label: "Yes" }],
value: 0
}
});
expect(Select.vm.findOptionFromReducedValue(option)).toEqual(option);
expect(Select.vm.selectedValue).toEqual([option]);
});
it('works with null values', () => {
const option = {value: null, label: 'No'};
it("works with null values", () => {
const option = { value: null, label: "No" };
const Select = shallowMount(VueSelect, {
propsData: {
reduce: option => option.value,
options: [option, {value: 1, label: 'Yes'}],
value: null,
},
options: [option, { value: 1, label: "Yes" }],
value: null
}
});
expect(Select.vm.findOptionFromReducedValue(option)).toEqual(option);
@@ -233,7 +248,6 @@ describe("When reduce prop is defined", () => {
Select.vm.select(nestedOption);
expect(Select.vm.isOptionSelected(nestedOption)).toEqual(true);
});
});
it("reacts correctly when value property changes", async () => {
@@ -252,10 +266,10 @@ describe("When reduce prop is defined", () => {
expect(Select.vm.selectedValue).toEqual([optionToChangeTo]);
});
describe('Reducing Tags', () => {
it('tracks values that have been created by the user', async () => {
describe("Reducing Tags", () => {
it("tracks values that have been created by the user", async () => {
const Parent = mount({
data: () => ({selected: null, options: []}),
data: () => ({ selected: null, options: [] }),
template: `
<v-select
v-model="selected"
@@ -265,7 +279,7 @@ describe("When reduce prop is defined", () => {
:create-option="label => ({ label, value: -1 })"
/>
`,
components: {'v-select': VueSelect},
components: { "v-select": VueSelect }
});
const Select = Parent.vm.$children[0];
@@ -273,15 +287,15 @@ describe("When reduce prop is defined", () => {
Select.$refs.search.focus();
await Select.$nextTick();
Select.search = 'hello';
Select.search = "hello";
await Select.$nextTick();
Select.typeAheadSelect();
await Select.$nextTick();
// Then
expect(Select.selectedValue).toEqual([{label: 'hello', value: -1}]);
expect(Select.$refs.selectedOptions.textContent.trim()).toEqual('hello');
expect(Select.selectedValue).toEqual([{ label: "hello", value: -1 }]);
expect(Select.$refs.selectedOptions.textContent.trim()).toEqual("hello");
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 () => {
const Select = selectWithProps({
options: ["one", "two", "three"],
selectable: (option) => option === "one"
selectable: option => option === "one"
});
Select.vm.$data.open = true;
@@ -14,12 +14,12 @@ describe("Selectable prop", () => {
await Select.vm.$nextTick();
expect(Select.vm.selectedValue).toEqual(["one"]);
})
});
it("should not select not selectable option if clicked", async () => {
const Select = selectWithProps({
options: ["one", "two", "three"],
selectable: (option) => option === "one"
selectable: option => option === "one"
});
Select.vm.$data.open = true;
@@ -34,7 +34,7 @@ describe("Selectable prop", () => {
it("should skip non-selectable option on down arrow keyDown", () => {
const Select = selectWithProps({
options: ["one", "two", "three"],
selectable: (option) => option !== "two"
selectable: option => option !== "two"
});
Select.vm.typeAheadPointer = 1;
@@ -42,12 +42,12 @@ describe("Selectable prop", () => {
Select.find({ ref: "search" }).trigger("keydown.down");
expect(Select.vm.typeAheadPointer).toEqual(2);
})
});
it("should skip non-selectable option on up arrow keyDown", () => {
const Select = selectWithProps({
options: ["one", "two", "three"],
selectable: (option) => option !== "two"
selectable: option => option !== "two"
});
Select.vm.typeAheadPointer = 2;
@@ -55,5 +55,5 @@ describe("Selectable prop", () => {
Select.find({ ref: "search" }).trigger("keydown.up");
expect(Select.vm.typeAheadPointer).toEqual(0);
})
})
});
});
+30 -11
View File
@@ -1,6 +1,6 @@
import { mount, shallowMount } from "@vue/test-utils";
import VueSelect from "../../src/components/Select.vue";
import { mountDefault } from '../helpers';
import { mountDefault } from "../helpers";
describe("VS - Selecting Values", () => {
let defaultProps;
@@ -81,7 +81,9 @@ describe("VS - Selecting Values", () => {
];
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", () => {
@@ -193,15 +195,20 @@ describe("VS - Selecting Values", () => {
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', () => {
const options = [{label: 'one', id: 1}, {label: 'one', id: 2}];
const Select = mountDefault({options, multiple: true});
it("can select two options with the same label", () => {
const options = [
{ 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: 2});
Select.vm.select({ label: "one", id: 1 });
Select.vm.select({ label: "one", id: 2 });
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", () => {
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");
@@ -257,7 +268,11 @@ describe("VS - Selecting Values", () => {
it("will trigger the option:selecting event regardless of current value when multiple is true", () => {
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");
@@ -293,7 +308,11 @@ describe("VS - Selecting Values", () => {
it("will trigger the option:selected event regardless of current value when multiple is true", () => {
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");
+99 -68
View File
@@ -1,122 +1,153 @@
import { mountDefault } from '../helpers';
import { mountDefault } from "../helpers";
describe('Scoped Slots', () => {
it('receives an option object to the selected-option-container slot', () => {
describe("Scoped Slots", () => {
it("receives an option object to the selected-option-container slot", () => {
const Select = mountDefault(
{value: 'one'},
{ value: "one" },
{
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', () => {
it('receives an option object to the selected-option slot', () => {
describe("Slot: selected-option", () => {
it("receives an option object to the selected-option slot", () => {
const Select = mountDefault(
{value: 'one'},
{ value: "one" },
{
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',
() => {
const Select = mountDefault(
{value: 'one'},
{
scopedSlots: {
'selected-option': `<span class="my-option" slot-scope="option">{{ option.label }}</span>`,
},
});
it("opens the dropdown when clicking an option in selected-option slot", () => {
const Select = mountDefault(
{ value: "one" },
{
scopedSlots: {
"selected-option": `<span class="my-option" slot-scope="option">{{ option.label }}</span>`
}
}
);
Select.find('.my-option').trigger('mousedown');
expect(Select.vm.open).toEqual(true);
});
Select.find(".my-option").trigger("mousedown");
expect(Select.vm.open).toEqual(true);
});
});
it('receives an option object to the option slot in the dropdown menu',
async () => {
const Select = mountDefault(
{value: 'one'},
{
scopedSlots: {
'option': `<span slot="option" slot-scope="option">{{ option.label }}</span>`,
},
});
it("receives an option object to the option slot in the dropdown menu", async () => {
const Select = mountDefault(
{ value: "one" },
{
scopedSlots: {
option: `<span slot="option" slot-scope="option">{{ option.label }}</span>`
}
}
);
Select.vm.open = true;
await Select.vm.$nextTick();
Select.vm.open = true;
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 Select = mountDefault({}, {
scopedSlots: {'no-options': noOptions},
});
const Select = mountDefault(
{},
{
scopedSlots: { "no-options": noOptions }
}
);
Select.vm.search = 'something not there';
Select.vm.search = "something not there";
Select.vm.open = true;
await Select.vm.$nextTick();
expect(noOptions).toHaveBeenCalledWith({
loading: false,
search: 'something not there',
searching: true,
})
search: "something not there",
searching: true
});
});
test('header slot props', async () => {
test("header slot props", async () => {
const header = jest.fn();
const Select = mountDefault({}, {
scopedSlots: {header: header},
});
const Select = mountDefault(
{},
{
scopedSlots: { header: header }
}
);
await Select.vm.$nextTick();
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 Select = mountDefault({}, {
scopedSlots: {footer: footer},
});
const Select = mountDefault(
{},
{
scopedSlots: { footer: footer }
}
);
await Select.vm.$nextTick();
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 Select = mountDefault({}, {
scopedSlots: {'list-header': header},
});
const Select = mountDefault(
{},
{
scopedSlots: { "list-header": header }
}
);
Select.vm.open = true;
await Select.vm.$nextTick();
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 Select = mountDefault({}, {
scopedSlots: {'list-footer': footer},
});
const Select = mountDefault(
{},
{
scopedSlots: { "list-footer": footer }
}
);
Select.vm.open = true;
await Select.vm.$nextTick();
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,
searchSubmit,
selectTag,
selectWithProps,
} from '../helpers';
import Select from '../../src/components/Select';
selectWithProps
} from "../helpers";
import Select from "../../src/components/Select";
describe("When Tagging Is Enabled", () => {
it("can determine if a given option string already exists", () => {
const Select = selectWithProps({ taggable: true, options: ["one", "two"] });
expect(Select.vm.optionExists("one")).toEqual(true);
@@ -20,8 +19,8 @@ describe("When Tagging Is Enabled", () => {
options: [{ label: "one" }, { label: "two" }]
});
expect(Select.vm.optionExists({label: "one"})).toEqual(true);
expect(Select.vm.optionExists({label: "three"})).toEqual(false);
expect(Select.vm.optionExists({ label: "one" })).toEqual(true);
expect(Select.vm.optionExists({ label: "three" })).toEqual(false);
});
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"
});
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("three"))).toEqual(false);
@@ -71,9 +70,7 @@ describe("When Tagging Is Enabled", () => {
await selectTag(Select, "two");
expect(Select.vm.selectedValue).toEqual([
{ label: "two" }
]);
expect(Select.vm.selectedValue).toEqual([{ label: "two" }]);
});
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,
options: [{ label: "two" }]
});
const spy = jest.spyOn(Select.vm, 'select');
const spy = jest.spyOn(Select.vm, "select");
await selectTag(Select, "one");
expect(Select.vm.selectedValue).toEqual([{ label: "one" }]);
expect(spy).lastCalledWith({label: 'one'});
expect(spy).lastCalledWith({ label: "one" });
expect(Select.vm.search).toEqual("");
await selectTag(Select, "one");
@@ -258,6 +255,6 @@ describe("When Tagging Is Enabled", () => {
Select.find({ ref: "search" }).trigger("keydown.tab");
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', () => {
expect(sortAndStringify({hello: 'world'})).toEqual('{"hello":"world"}');
test("it will stringify an object", () => {
expect(sortAndStringify({ hello: "world" })).toEqual('{"hello":"world"}');
});
test('it will sort attributes alphabetically', () => {
expect(sortAndStringify({b: 'b', a: 'a'})).toEqual('{"a":"a","b":"b"}');
test("it will sort attributes alphabetically", () => {
expect(sortAndStringify({ b: "b", a: "a" })).toEqual('{"a":"a","b":"b"}');
});
test('comparing two objects with unsorted keys', () => {
expect(sortAndStringify({b: 'b', a: 'a'}))
.toEqual(sortAndStringify({a: 'a', b: 'b'}))
test("comparing two objects with unsorted keys", () => {
expect(sortAndStringify({ b: "b", a: "a" })).toEqual(
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());
});