2
0
mirror of https://github.com/tenrok/vue-select.git synced 2026-05-17 02:29:37 +03:00

build(vite): replace webpack with Vite, add Typescript (#1594)

BREAKING: mixins are no longer exported from the index (and will likely be converted to hooks)
This commit is contained in:
Jeff Sagal
2022-07-18 09:33:46 -07:00
committed by GitHub
parent 92abcbf1f8
commit 98c278b2bb
51 changed files with 3470 additions and 10062 deletions
-19
View File
@@ -1,19 +0,0 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
[*.{js,vue}]
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
+15
View File
@@ -0,0 +1,15 @@
/* eslint-env node */
require("@rushstack/eslint-patch/modern-module-resolution");
module.exports = {
"root": true,
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/eslint-config-typescript/recommended",
"@vue/eslint-config-prettier"
],
"env": {
"vue/setup-compiler-macros": true
}
}
-22
View File
@@ -1,22 +0,0 @@
module.exports = {
parser: 'vue-eslint-parser',
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module',
},
plugins: ['prettier'],
extends: [
'plugin:prettier/recommended',
'plugin:vue/recommended',
'prettier/vue',
],
ignorePatterns: [
'!.*.js',
'!docs/.vuepress',
'docs/.vuepress/dist',
'node_modules',
'dist',
'coverage',
'yarn.lock',
],
}
+11 -4
View File
@@ -9,15 +9,22 @@ jobs:
release:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 12
node-version: 16
cache: yarn
- uses: actions/cache@v3
id: yarn-cache
with:
path: node_modules
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: ${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Test with Coverage
- name: Test
run: yarn test
- name: Build
+26 -12
View File
@@ -4,16 +4,23 @@ jobs:
test:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 12
node-version: 16
cache: yarn
- uses: actions/cache@v3
id: yarn-cache
with:
path: node_modules
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: ${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Test with Coverage
run: yarn test --coverage --coverageReporters=lcov
run: yarn coverage
- name: ESLint
run: yarn eslint
@@ -26,16 +33,20 @@ jobs:
build:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 12
node-version: 16
cache: yarn
- uses: actions/cache@v3
id: yarn-cache
with:
path: '**/node_modules'
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: ${{ runner.os }}-yarn-
- name: Install dependencies
run: |
yarn install --frozen-lockfile
cd docs
yarn install --frozen-lockfile
run: yarn install --frozen-lockfile --prefer-offline
- name: Build Dist
run: yarn build
@@ -44,4 +55,7 @@ jobs:
run: npx bundlewatch
- name: Build Docs
run: yarn build:docs
run: |
cd docs
yarn install --frozen-lockfile --prefer-offline
yarn build
+7 -1
View File
@@ -7,6 +7,10 @@ node_modules
.env.*.local
# Log files
logs
*.log
pnpm-debug.log*
lerna-debug.log*
npm-debug.log*
yarn-debug.log*
yarn-error.log*
@@ -26,5 +30,7 @@ dist
test/unit/coverage
package-lock.json
dev/dist
docs/.vuepress/dist
dist-ssr
*.local
.netlify
docs/.vuepress/dist
-71
View File
@@ -1,71 +0,0 @@
const path = require('path')
const webpack = require('webpack')
const VueLoaderPlugin = require('vue-loader').VueLoaderPlugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const env = process.env.NODE_ENV === 'production' ? 'production' : 'development'
const devtool = env === 'production' ? 'source-map' : 'eval-source-map'
const extractOrInjectStyles =
env !== 'production' ? 'vue-style-loader' : MiniCssExtractPlugin.loader
module.exports = {
mode: env,
output: {
path: path.resolve(__dirname, '../dist'),
publicPath: '/',
filename: '[name].js',
},
devtool,
resolve: {
extensions: ['.js', '.vue'],
alias: {
src: path.resolve(__dirname, '../src'),
assets: path.resolve(__dirname, '../docs/assets'),
mixins: path.resolve(__dirname, '../src/mixins'),
components: path.resolve(__dirname, '../src/components'),
vue$: 'vue/dist/vue.runtime.esm-bundler.js',
},
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test: /\.js$/,
loader: 'babel-loader',
include: path.resolve(__dirname, '../'),
exclude: /node_modules/,
},
{
test: /\.css$/i,
use: [
extractOrInjectStyles,
{
loader: 'css-loader',
options: { importLoaders: 1 },
},
'postcss-loader',
],
},
],
},
plugins: [
new webpack.DefinePlugin({
'process.env': env,
__VUE_OPTIONS_API__: true,
__VUE_PROD_DEVTOOLS__: false,
}),
new MiniCssExtractPlugin({
filename: 'vue-select.css',
}),
new VueLoaderPlugin(),
],
stats: {
children: false,
modules: false,
},
}
-21
View File
@@ -1,21 +0,0 @@
const { merge } = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const baseWebpackConfig = require('./webpack.base.conf')
module.exports = merge(baseWebpackConfig, {
entry: './dev/dev.js',
devServer: {
open: true,
static: false,
client: { overlay: true },
watchFiles: ['dev/dev.html'],
},
stats: false,
plugins: [
new HtmlWebpackPlugin({
title: 'dev',
template: './dev/dev.html',
inject: true,
}),
],
})
-20
View File
@@ -1,20 +0,0 @@
const TerserPlugin = require('terser-webpack-plugin')
const { merge } = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
module.exports = merge(baseWebpackConfig, {
entry: './src/index.js',
output: {
filename: 'vue-select.js',
library: 'VueSelect',
libraryTarget: 'umd',
globalObject: "typeof self !== 'undefined' ? self : this",
},
externals: {
vue: 'vue',
},
optimization: {
minimize: true,
minimizer: [new TerserPlugin()],
},
})
+2 -3
View File
@@ -5,9 +5,8 @@
</template>
<script>
import vSelect from '../src/components/Select'
import countries from '../docs/.vuepress/data/countryCodes'
import books from '../docs/.vuepress/data/books'
import vSelect from '@/components/Select.vue'
import countries from '../docs/.vuepress/data/countryCodes.js'
export default {
components: { vSelect },
-15
View File
@@ -1,15 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Vue Select Dev</title>
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
<!--<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.5.3/css/foundation.min.css">-->
<!--<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.min.css">-->
<!--<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">-->
<!--<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css">-->
</head>
<body>
<div id="app"></div>
</body>
</html>
+1 -3
View File
@@ -1,6 +1,4 @@
import { createApp, h } from 'vue'
import Dev from './Dev.vue'
createApp({
render: () => h(Dev),
}).mount('#app')
createApp(Dev).mount('#app')
+8
View File
@@ -2,6 +2,7 @@ const { description } = require('./config/meta')
const head = require('./config/head')
const plugins = require('./config/plugins')
const themeConfig = require('./config/themeConfig')
const { resolve } = require('path')
module.exports = {
title: 'Vue Select',
@@ -9,4 +10,11 @@ module.exports = {
head,
plugins,
themeConfig,
configureWebpack: {
resolve: {
alias: {
'@': resolve(__dirname, '../../src'),
},
},
},
}
Vendored
+1
View File
@@ -0,0 +1 @@
/// <reference types="vite/client" />
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue Select Dev</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./dev/dev.js"></script>
</body>
</html>
+10
View File
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@tests/*": ["tests/*"]
}
},
"exclude": ["node_modules", "dist", "coverage", "docs"]
}
+95 -134
View File
@@ -1,138 +1,99 @@
{
"name": "vue-select",
"version": "4.0.0-beta.3",
"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",
"scripts": {
"serve": "webpack-dev-server --config build/webpack.dev.conf.js --hot --progress",
"serve:docs": "cd docs && yarn serve",
"build": "cross-env NODE_ENV=production webpack --config build/webpack.prod.conf.js --progress",
"build:docs": "cd docs && yarn build",
"build:preview": "cd docs && yarn build",
"test": "jest",
"eslint": "eslint '{**/*,*}.{js,ts,jsx,tsx,vue}'",
"eslint:fix": "npm run eslint -- --fix",
"semantic-release": "semantic-release",
"commit": "git-cz"
},
"repository": {
"type": "git",
"url": "https://github.com/sagalbot/vue-select.git"
},
"peerDependencies": {
"vue": "3.x"
},
"devDependencies": {
"@babel/core": "^7.4.0",
"@babel/eslint-parser": "^7.14.7",
"@babel/plugin-transform-runtime": "^7.4.0",
"@babel/preset-env": "^7.4.2",
"@babel/runtime": "^7.4.2",
"@semantic-release/git": "^9.0.0",
"@semantic-release/github": "^7.0.4",
"@vue/compiler-sfc": "^3.2.20",
"@vue/test-utils": "^2.0.0-rc.17",
"autoprefixer": "^10.3.7",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.0.3",
"babel-loader": "^8.0.5",
"bundlewatch": "^0.2.5",
"commitizen": "^4.0.3",
"coveralls": "^3.1.1",
"cross-env": "^5.2.0",
"css-loader": "^6.4.0",
"cssnano": "^5.0.8",
"cz-conventional-changelog": "3.1.0",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.0",
"eslint-loader": "^3.0.3",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-vue": "^6.2.1",
"html-loader": "^3.1.0",
"html-webpack-plugin": "^5.5.0",
"jest": "^24.1.0",
"jest-serializer-vue": "^2.0.2",
"jest-transform-stub": "^2.0.0",
"mini-css-extract-plugin": "^2.5.3",
"postcss": "^8.3.11",
"postcss-import": "^14.0.2",
"postcss-loader": "^6.2.1",
"postcss-nested": "^5.0.6",
"prettier": "2.2.1",
"semantic-release": "^17.0.4",
"terser-webpack-plugin": "^5.2.4",
"url-loader": "^4.1.1",
"vue": "^3.2.20",
"vue-html-loader": "^1.2.4",
"vue-jest": "5.0.0-alpha.8",
"vue-loader": "^16.8.1",
"vue-server-renderer": "^2.6.10",
"vue-style-loader": "^4.1.3",
"vue-template-compiler": "^2.6.10",
"webpack": "^5.69.1",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.4",
"webpack-merge": "^5.8.0"
},
"jest": {
"moduleFileExtensions": [
"js",
"jsx",
"json",
"vue"
],
"transform": {
"^.+\\.vue$": "vue-jest",
".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub",
"^.+\\.jsx?$": "babel-jest"
"name": "vue-select",
"version": "4.0.0-beta.3",
"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"
},
"moduleNameMapper": {
"^@/(.*)$": "<rootDir>/src/$1"
},
"snapshotSerializers": [
"jest-serializer-vue"
],
"testMatch": [
"**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"
],
"testURL": "http://localhost/",
"collectCoverage": true,
"collectCoverageFrom": [
"src/mixins/*.js",
"!src/mixins/index.js",
"src/components/Select.vue",
"!**/node_modules/**"
],
"coverageReporters": [
"text"
]
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
},
"bundlewatch": {
"files": [
{
"path": "./dist/vue-select.js",
"compression": "none",
"maxSize": "23 KB"
},
{
"path": "./dist/vue-select.css",
"compression": "none",
"maxSize": "8 KB"
}
]
}
"dist"
],
"main": "./dist/vue-select.umd.js",
"module": "./dist/vue-select.es.js",
"exports": {
".": {
"import": "./dist/vue-select.es.js",
"require": "./dist/vue-select.umd.js"
}
},
"private": false,
"license": "MIT",
"prepare": "npm run build",
"scripts": {
"dev:docs": "cd docs && yarn serve",
"build:docs": "cd docs && yarn build",
"semantic-release": "semantic-release",
"commit": "git-cz",
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview --port 5050",
"test": "vitest --environment jsdom",
"coverage": "vitest --run --coverage --environment jsdom --silent",
"typecheck": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
},
"repository": {
"type": "git",
"url": "https://github.com/sagalbot/vue-select.git"
},
"peerDependencies": {
"vue": "3.x"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.1.4",
"@semantic-release/git": "^10.0.1",
"@semantic-release/github": "^8.0.5",
"@types/jsdom": "^16.2.14",
"@types/node": "^18.0.5",
"@vitejs/plugin-vue": "^3.0.0",
"@vue/eslint-config-prettier": "^7.0.0",
"@vue/eslint-config-typescript": "^11.0.0",
"@vue/test-utils": "^2.0.2",
"@vue/tsconfig": "^0.1.3",
"autoprefixer": "^10.4.7",
"bundlewatch": "^0.3.3",
"c8": "^7.11.3",
"commitizen": "^4.2.5",
"coveralls": "^3.1.1",
"cross-env": "^7.0.3",
"cz-conventional-changelog": "3.3.0",
"eslint": "^8.20.0",
"eslint-plugin-vue": "^9.2.0",
"jsdom": "^20.0.0",
"postcss-nested": "^5.0.6",
"prettier": "^2.7.1",
"semantic-release": "^19.0.3",
"typescript": "^4.7.4",
"vite": "^3.0.0",
"vitest": "^0.18.1",
"vue": "^3.2.37",
"vue-tsc": "^0.38.8"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
},
"bundlewatch": {
"files": [
{
"path": "./dist/vue-select.es.js",
"compression": "gzip",
"maxSize": "8 KB"
},
{
"path": "./dist/vue-select.umd.js",
"compression": "gzip",
"maxSize": "7 KB"
},
{
"path": "./dist/vue-select.css",
"compression": "gzip",
"maxSize": "2 KB"
}
]
}
}
+1 -8
View File
@@ -1,10 +1,3 @@
module.exports = {
plugins: [
require('postcss-import'),
require('autoprefixer'),
require('postcss-nested'),
require('cssnano')({
preset: 'default',
}),
],
plugins: [require('autoprefixer'), require('postcss-nested')],
}
+11 -11
View File
@@ -136,13 +136,13 @@
</template>
<script>
import pointerScroll from '../mixins/pointerScroll'
import typeAheadPointer from '../mixins/typeAheadPointer'
import ajax from '../mixins/ajax'
import childComponents from './childComponents'
import appendToBody from '../directives/appendToBody'
import sortAndStringify from '../utility/sortAndStringify'
import uniqueId from '../utility/uniqueId'
import pointerScroll from '@/mixins/pointerScroll.js'
import typeAheadPointer from '@/mixins/typeAheadPointer.js'
import ajax from '@/mixins/ajax.js'
import childComponents from '@/components/childComponents.js'
import appendToBody from '@/directives/appendToBody.js'
import sortAndStringify from '@/utility/sortAndStringify.js'
import uniqueId from '@/utility/uniqueId.js'
/**
* @name VueSelect
@@ -722,7 +722,7 @@ export default {
value = this.$data._value
}
if (value !== undefined && value !== null) {
if (value !== undefined && value !== null && value !== '') {
return [].concat(value)
}
@@ -745,7 +745,7 @@ export default {
* @returns {HTMLInputElement}
*/
searchEl() {
return !!this.$slots['search']
return this.$slots['search']
? this.$refs.selectedOptions.querySelector(
this.searchInputQuerySelector
)
@@ -890,7 +890,7 @@ export default {
return optionList
}
let options = this.search.length
const options = this.search.length
? this.filter(optionList, this.search, this)
: optionList
if (this.taggable && this.search.length) {
@@ -930,7 +930,7 @@ export default {
* @return {[type]} [description]
*/
options(newOptions, oldOptions) {
let shouldReset = () =>
const shouldReset = () =>
typeof this.resetOnOptionsChange === 'function'
? this.resetOnOptionsChange(
newOptions,
+2 -2
View File
@@ -1,5 +1,5 @@
import Deselect from './Deselect'
import OpenIndicator from './OpenIndicator'
import Deselect from './Deselect.vue'
import OpenIndicator from './OpenIndicator.vue'
export default {
Deselect,
-2
View File
@@ -1,5 +1,3 @@
import VueSelect from './components/Select.vue'
import mixins from './mixins/index'
export default VueSelect
export { VueSelect, mixins }
+3 -3
View File
@@ -1,5 +1,5 @@
import ajax from './ajax'
import pointer from './typeAheadPointer'
import pointerScroll from './pointerScroll'
import ajax from '@/mixins/ajax.js'
import pointer from '@/mixins/typeAheadPointer.js'
import pointerScroll from '@/mixins/pointerScroll.js'
export default { ajax, pointer, pointerScroll }
+1 -20
View File
@@ -1,6 +1,5 @@
import { shallowMount } from '@vue/test-utils'
import VueSelect from '../src/components/Select.vue'
import Vue from 'vue'
import VueSelect from '@/components/Select.vue'
/**
* Trigger a submit event on the search
@@ -69,21 +68,3 @@ export const mountDefault = (props = {}, options = {}) => {
...options,
})
}
/**
* Returns a v-select component directly.
* @param props
* @param options
* @return {Vue | Element | Vue[] | Element[]}
*/
export const mountWithoutTestUtils = (props = {}, options = {}) => {
return createApp({
render: (createEl) =>
createEl('vue-select', {
ref: 'select',
props: { options: ['one', 'two', 'three'], ...props },
...options,
}),
components: { VueSelect },
}).mount().$refs.select
}
+3 -2
View File
@@ -1,10 +1,11 @@
import { mountDefault } from '../helpers'
import { it, describe, expect } from 'vitest'
import { mountDefault } from '@tests/helpers.js'
describe('Search Slot Scope', () => {
/**
* @see https://www.w3.org/WAI/PF/aria/states_and_properties#aria-activedescendant
*/
fdescribe('aria-activedescendant', () => {
describe('aria-activedescendant', () => {
it('adds the active descendant attribute only when the dropdown is open and there is a typeAheadPointer value', async () => {
const Select = mountDefault()
+3 -2
View File
@@ -1,6 +1,7 @@
import { selectWithProps } from '../helpers'
import { it, describe, expect } from 'vitest'
import { selectWithProps } from '@tests/helpers.js'
import { shallowMount } from '@vue/test-utils'
import vSelect from '../../src/components/Select'
import vSelect from '@/components/Select.vue'
describe('Asynchronous Loading', () => {
it('can toggle the loading class', () => {
+8 -6
View File
@@ -1,15 +1,17 @@
import pointerScroll from '../../src/mixins/pointerScroll'
import { mountDefault } from '../helpers'
import { it, describe, expect, vi, afterEach } from 'vitest'
import pointerScroll from '@/mixins/pointerScroll.js'
import { mountDefault } from '@tests/helpers.js'
describe('Automatic Scrolling', () => {
let spy
afterEach(() => {
if (spy) spy.mockClear()
})
it('should check if the scroll position needs to be adjusted on up arrow keyUp', async () => {
// Given
spy = jest.spyOn(pointerScroll.methods, 'maybeAdjustScroll')
spy = vi.spyOn(pointerScroll.methods, 'maybeAdjustScroll')
const Select = mountDefault()
Select.vm.typeAheadPointer = 1
@@ -22,7 +24,7 @@ describe('Automatic Scrolling', () => {
it('should check if the scroll position needs to be adjusted on down arrow keyUp', async () => {
// Given
spy = jest.spyOn(pointerScroll.methods, 'maybeAdjustScroll')
spy = vi.spyOn(pointerScroll.methods, 'maybeAdjustScroll')
const Select = mountDefault()
Select.vm.typeAheadPointer = 1
@@ -35,7 +37,7 @@ describe('Automatic Scrolling', () => {
it('should check if the scroll position needs to be adjusted when filtered options changes', async () => {
// Given
spy = jest.spyOn(pointerScroll.methods, 'maybeAdjustScroll')
spy = vi.spyOn(pointerScroll.methods, 'maybeAdjustScroll')
const Select = mountDefault()
Select.vm.typeAheadPointer = 1
@@ -49,7 +51,7 @@ describe('Automatic Scrolling', () => {
it('should not adjust scroll position when autoscroll is false', async () => {
// Given
spy = jest.spyOn(pointerScroll.methods, 'maybeAdjustScroll')
spy = vi.spyOn(pointerScroll.methods, 'maybeAdjustScroll')
const Select = mountDefault({
autoscroll: false,
})
+2 -1
View File
@@ -1,5 +1,6 @@
import { it, describe, expect } from 'vitest'
import { defineComponent } from 'vue'
import { selectWithProps } from '../helpers'
import { selectWithProps } from '@tests/helpers.js'
describe('Components API', () => {
it('swap the Deselect component', () => {
+2 -1
View File
@@ -1,4 +1,5 @@
import { selectTag, selectWithProps } from '../helpers'
import { it, describe, expect } from 'vitest'
import { selectTag, selectWithProps } from '@tests/helpers.js'
describe('CreateOption When Tagging Is Enabled', () => {
it('can select the current search text as a string', async () => {
+5 -4
View File
@@ -1,4 +1,5 @@
import { mountDefault, selectWithProps } from '../helpers'
import { it, describe, expect, vi } from 'vitest'
import { mountDefault, selectWithProps } from '@tests/helpers.js'
describe('Removing values', () => {
it('can remove the given tag when its close icon is clicked', async () => {
@@ -65,7 +66,7 @@ describe('Removing values', () => {
options: ['one', 'two', 'three'],
deselectFromDropdown: true,
})
const deselect = spyOn(Select.vm, 'deselect')
const deselect = vi.spyOn(Select.vm, 'deselect')
Select.vm.open = true
await Select.vm.$nextTick()
@@ -83,7 +84,7 @@ describe('Removing values', () => {
clearable: false,
deselectFromDropdown: true,
})
const deselect = spyOn(Select.vm, 'deselect')
const deselect = vi.spyOn(Select.vm, 'deselect')
Select.vm.open = true
await Select.vm.$nextTick()
@@ -100,7 +101,7 @@ describe('Removing values', () => {
options: ['one', 'two', 'three'],
deselectFromDropdown: false,
})
const deselect = spyOn(Select.vm, 'deselect')
const deselect = vi.spyOn(Select.vm, 'deselect')
Select.vm.open = true
await Select.vm.$nextTick()
+9 -21
View File
@@ -1,8 +1,9 @@
import { selectWithProps } from '../helpers'
import OpenIndicator from '../../src/components/OpenIndicator'
import VueSelect from '../../src/components/Select'
import { it, describe, expect, vi, afterEach } from 'vitest'
import { selectWithProps } from '@tests/helpers.js'
import OpenIndicator from '@/components/OpenIndicator.vue'
import VueSelect from '@/components/Select.vue'
const preventDefault = jest.fn()
const preventDefault = vi.fn()
function clickEvent(currentTarget) {
return { currentTarget, preventDefault }
@@ -30,19 +31,6 @@ describe('Toggling Dropdown', () => {
expect(Select.vm.open).toEqual(true)
})
it('should not close the dropdown when the el is clicked and enableMouseInputSearch is set to true', () => {
const Select = selectWithProps({
modelValue: [{ label: 'one' }],
options: [{ label: 'one' }],
enableMouseSearchInput: true,
})
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)
})
it('should open the dropdown when the selected tag is clicked', () => {
const Select = selectWithProps({
modelValue: [{ label: 'one' }],
@@ -57,7 +45,7 @@ describe('Toggling Dropdown', () => {
it('can close the dropdown when the el is clicked', () => {
const Select = selectWithProps()
const spy = jest.spyOn(Select.vm.$refs.search, 'blur')
const spy = vi.spyOn(Select.vm.$refs.search, 'blur')
Select.vm.open = true
Select.vm.toggleDropdown(clickEvent(Select.vm.$el))
@@ -104,7 +92,7 @@ describe('Toggling Dropdown', () => {
})
it('will close the dropdown and emit the search:blur event from onSearchBlur', () => {
spy = jest.spyOn(VueSelect.methods, 'onSearchBlur')
spy = vi.spyOn(VueSelect.methods, 'onSearchBlur')
const Select = selectWithProps()
Select.vm.open = true
@@ -115,7 +103,7 @@ describe('Toggling Dropdown', () => {
})
it('will open the dropdown and emit the search:focus event from onSearchFocus', () => {
spy = jest.spyOn(VueSelect.methods, 'onSearchFocus')
spy = vi.spyOn(VueSelect.methods, 'onSearchFocus')
const Select = selectWithProps()
Select.vm.onSearchFocus()
@@ -126,7 +114,7 @@ describe('Toggling Dropdown', () => {
it('will close the dropdown on escape, if search is empty', () => {
const Select = selectWithProps()
const spy = jest.spyOn(Select.vm.$refs.search, 'blur')
const spy = vi.spyOn(Select.vm.$refs.search, 'blur')
Select.vm.open = true
Select.vm.onEscape()
+2 -1
View File
@@ -1,5 +1,6 @@
import { it, describe, expect } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import VueSelect from '../../src/components/Select'
import VueSelect from '@/components/Select.vue'
describe('Filtering Options', () => {
it("should update the search value when the input element receives the 'input' event", () => {
+9 -9
View File
@@ -1,6 +1,6 @@
import { DOMWrapper } from '@vue/test-utils'
import typeAheadPointer from '../../src/mixins/typeAheadPointer'
import { mountDefault } from '../helpers'
import { it, describe, expect, vi, afterEach } from 'vitest'
import typeAheadPointer from '@/mixins/typeAheadPointer.js'
import { mountDefault } from '@tests/helpers.js'
describe('Custom Keydown Handlers', () => {
let spy
@@ -9,7 +9,7 @@ describe('Custom Keydown Handlers', () => {
})
it('can use the map-keydown prop to trigger custom behaviour', async () => {
const onKeyDown = jest.fn()
const onKeyDown = vi.fn()
const Select = mountDefault({
mapKeydown: (defaults, vm) => ({ ...defaults, 32: onKeyDown }),
})
@@ -20,7 +20,7 @@ describe('Custom Keydown Handlers', () => {
})
it('selectOnKeyCodes should trigger a selection for custom keycodes', () => {
spy = jest.spyOn(typeAheadPointer.methods, 'typeAheadSelect')
spy = vi.spyOn(typeAheadPointer.methods, 'typeAheadSelect')
const Select = mountDefault({
selectOnKeyCodes: [32],
@@ -32,9 +32,9 @@ describe('Custom Keydown Handlers', () => {
})
it('even works when combining selectOnKeyCodes with map-keydown', () => {
spy = jest.spyOn(typeAheadPointer.methods, 'typeAheadSelect')
spy = vi.spyOn(typeAheadPointer.methods, 'typeAheadSelect')
const onKeyDown = jest.fn()
const onKeyDown = vi.fn()
const Select = mountDefault({
mapKeydown: (defaults, vm) => ({ ...defaults, 32: onKeyDown }),
selectOnKeyCodes: [9],
@@ -49,7 +49,7 @@ describe('Custom Keydown Handlers', () => {
describe('CompositionEvent support', () => {
it('will not select a value with enter if the user is composing', () => {
spy = jest.spyOn(typeAheadPointer.methods, 'typeAheadSelect')
spy = vi.spyOn(typeAheadPointer.methods, 'typeAheadSelect')
const Select = mountDefault()
@@ -63,7 +63,7 @@ describe('Custom Keydown Handlers', () => {
})
it('will not select a value with tab if the user is composing', () => {
spy = jest.spyOn(typeAheadPointer.methods, 'typeAheadSelect')
spy = vi.spyOn(typeAheadPointer.methods, 'typeAheadSelect')
const Select = mountDefault({ selectOnTab: true })
+22 -21
View File
@@ -1,6 +1,7 @@
import VueSelect from '../../src/components/Select'
import { it, describe, expect, vi } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import { selectWithProps } from '../helpers'
import VueSelect from '@/components/Select.vue'
import { selectWithProps } from '@tests/helpers.js'
describe('Labels', () => {
it('can generate labels using a custom label key', () => {
@@ -13,7 +14,7 @@ describe('Labels', () => {
})
it('will console.warn when options contain objects without a valid label key', async () => {
const spy = jest.spyOn(console, 'warn').mockImplementation(() => {})
const spy = vi.spyOn(console, 'warn').mockImplementation(() => {})
const Select = selectWithProps({
options: [{}],
})
@@ -63,23 +64,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')
const Select = shallowMount(VueSelect, {
props: {
options: [{ name: 'one' }],
filter: () => {},
},
scopedSlots: {
option: '<span class="option">{{ props.name }}</span>',
'selected-option': '<span class="selected">{{ props.name }}</span>',
},
})
Select.vm.select({ name: 'one' })
expect(spy).toHaveBeenCalledTimes(0)
expect(Select.find('.selected').exists()).toBeTruthy()
})
// it('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, {
// props: {
// options: [{ name: 'one' }],
// filter: () => {},
// },
// scopedSlots: {
// option: '<span class="option">{{ props.name }}</span>',
// 'selected-option': '<span class="selected">{{ props.name }}</span>',
// },
// })
//
// Select.vm.select({ name: 'one' })
//
// expect(spy).toHaveBeenCalledTimes(0)
// expect(Select.find('.selected').exists()).toBeTruthy()
// })
})
})
+2 -1
View File
@@ -1,5 +1,6 @@
import { it, describe, expect } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import VueSelect from '../../src/components/Select'
import VueSelect from '@/components/Select.vue'
describe('Single value options', () => {
it('should reset the search input on focus lost', () => {
+2 -1
View File
@@ -1,4 +1,5 @@
import Select from '../../src/components/Select'
import { it, describe, expect } from 'vitest'
import Select from '@/components/Select.vue'
describe('Comparing Options', () => {
const comparator = Select.methods.optionComparator.bind({
+2 -1
View File
@@ -1,4 +1,5 @@
import Select from '../../src/components/Select.vue'
import { it, describe, expect } from 'vitest'
import Select from '@/components/Select.vue'
describe('Serializing Option Keys', () => {
const getOptionKey = Select.props.getOptionKey.default
+14 -13
View File
@@ -1,6 +1,7 @@
import { mount, shallowMount } from '@vue/test-utils'
import VueSelect from '../../src/components/Select'
import { mountDefault } from '../helpers'
import { it, describe, expect, vi, afterEach } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import VueSelect from '@/components/Select.vue'
import { mountDefault } from '@tests/helpers.js'
describe('Reset on options change', () => {
it('should not reset the selected value by default when the options property changes', async () => {
@@ -21,7 +22,7 @@ describe('Reset on options change', () => {
})
it('will yell at you if resetOnOptionsChange is not a function or boolean', () => {
spy = jest.spyOn(console, 'warn').mockImplementation(() => {})
spy = vi.spyOn(console, 'warn').mockImplementation(() => {})
mountDefault({ resetOnOptionsChange: 1 })
expect(spy.mock.calls[0][0]).toContain(
@@ -45,7 +46,7 @@ describe('Reset on options change', () => {
})
it('should receive the new options, old options, and current value', async () => {
let resetOnOptionsChange = jest.fn((option) => option)
const resetOnOptionsChange = vi.fn((option) => option)
const Select = mountDefault({
resetOnOptionsChange,
options: ['bear'],
@@ -63,8 +64,8 @@ describe('Reset on options change', () => {
})
it('should allow resetOnOptionsChange to be a function that returns true', async () => {
let resetOnOptionsChange = () => true
spy = jest.spyOn(VueSelect.methods, 'clearSelection')
const resetOnOptionsChange = () => true
spy = vi.spyOn(VueSelect.methods, 'clearSelection')
const Select = shallowMount(VueSelect, {
props: { resetOnOptionsChange, options: ['one'], modelValue: 'one' },
})
@@ -75,8 +76,8 @@ describe('Reset on options change', () => {
})
it('should allow resetOnOptionsChange to be a function that returns false', () => {
let resetOnOptionsChange = () => false
spy = jest.spyOn(VueSelect.methods, 'clearSelection')
const resetOnOptionsChange = () => false
spy = vi.spyOn(VueSelect.methods, 'clearSelection')
const Select = shallowMount(VueSelect, {
props: { resetOnOptionsChange, options: ['one'], modelValue: 'one' },
})
@@ -86,9 +87,9 @@ describe('Reset on options change', () => {
})
it('should reset the options if the selectedValue does not exist in the new options', async () => {
let resetOnOptionsChange = (options, old, val) =>
const resetOnOptionsChange = (options, old, val) =>
val.some((val) => options.includes(val))
spy = jest.spyOn(VueSelect.methods, 'clearSelection')
spy = vi.spyOn(VueSelect.methods, 'clearSelection')
const Select = shallowMount(VueSelect, {
props: { resetOnOptionsChange, options: ['one'], modelValue: 'one' },
})
@@ -135,7 +136,7 @@ describe('Reset on options change', () => {
it('clearSearchOnBlur returns false when multiple is true', async () => {
const Select = mountDefault({})
let clearSearchOnBlur = jest.spyOn(Select.vm.$.props, 'clearSearchOnBlur')
const clearSearchOnBlur = vi.spyOn(Select.vm.$.props, 'clearSearchOnBlur')
await Select.get('input').trigger('click')
Select.vm.search = 'one'
await Select.get('input').trigger('blur')
@@ -149,7 +150,7 @@ describe('Reset on options change', () => {
})
it('clearSearchOnBlur accepts a function', async () => {
let clearSearchOnBlur = jest.fn(() => false)
const clearSearchOnBlur = vi.fn(() => false)
const Select = mountDefault({ clearSearchOnBlur })
await Select.get('input').trigger('click')
+4 -3
View File
@@ -1,10 +1,11 @@
import { it, describe, expect } from 'vitest'
import { mount, shallowMount } from '@vue/test-utils'
import VueSelect from '../../src/components/Select'
import { mountDefault } from '../helpers.js'
import VueSelect from '@/components/Select.vue'
import { mountDefault } from '@tests/helpers.js'
describe('When reduce prop is defined', () => {
it('determines when a reducer has been supplied', async () => {
let Select = mountDefault()
const Select = mountDefault()
expect(Select.vm.isReducingValues).toBeFalsy()
await Select.setProps({ reduce: () => {} })
+2 -1
View File
@@ -1,4 +1,5 @@
import { searchSubmit, selectWithProps } from '../helpers'
import { it, describe, expect } from 'vitest'
import { searchSubmit, selectWithProps } from '@tests/helpers.js'
describe('Selectable prop', () => {
it('should select selectable option if clicked', async () => {
+6 -5
View File
@@ -1,7 +1,8 @@
import { it, describe, expect, vi, beforeEach, afterEach } from 'vitest'
import { mount, shallowMount } from '@vue/test-utils'
import VueSelect from '../../src/components/Select.vue'
import typeAheadPointer from '../../src/mixins/typeAheadPointer'
import { mountDefault } from '../helpers'
import VueSelect from '@/components/Select.vue'
import typeAheadPointer from '@/mixins/typeAheadPointer.js'
import { mountDefault } from '@tests/helpers.js'
describe('VS - Selecting Values', () => {
let defaultProps
@@ -57,7 +58,7 @@ describe('VS - Selecting Values', () => {
})
it('can select an option on tab', () => {
spy = jest.spyOn(typeAheadPointer.methods, 'typeAheadSelect')
spy = vi.spyOn(typeAheadPointer.methods, 'typeAheadSelect')
const Select = shallowMount(VueSelect, {
props: {
selectOnTab: true,
@@ -218,7 +219,7 @@ describe('VS - Selecting Values', () => {
expect(Select.vm.selectedValue).toEqual(options)
})
fit('can select a false boolean option', async () => {
it('can select a false boolean option', async () => {
const Select = mountDefault({
options: [false],
})
+7 -6
View File
@@ -1,5 +1,6 @@
import { it, test, describe, expect, vi } from 'vitest'
import { h } from 'vue'
import { mountDefault } from '../helpers'
import { mountDefault } from '@tests/helpers.js'
describe('Scoped Slots', () => {
it('receives an option object to the selected-option-container slot', () => {
@@ -68,7 +69,7 @@ describe('Scoped Slots', () => {
})
it('noOptions slot receives the current search text', async () => {
const noOptions = jest.fn()
const noOptions = vi.fn()
const Select = mountDefault(
{},
{
@@ -88,7 +89,7 @@ describe('Scoped Slots', () => {
})
test('header slot props', async () => {
const header = jest.fn()
const header = vi.fn()
const Select = mountDefault(
{},
{
@@ -106,7 +107,7 @@ describe('Scoped Slots', () => {
})
test('footer slot props', async () => {
const footer = jest.fn()
const footer = vi.fn()
const Select = mountDefault(
{},
{
@@ -124,7 +125,7 @@ describe('Scoped Slots', () => {
})
test('list-header slot props', async () => {
const header = jest.fn()
const header = vi.fn()
const Select = mountDefault(
{},
{
@@ -142,7 +143,7 @@ describe('Scoped Slots', () => {
})
test('list-footer slot props', async () => {
const footer = jest.fn()
const footer = vi.fn()
const Select = mountDefault(
{},
{
+7 -6
View File
@@ -1,10 +1,11 @@
import { it, describe, expect, vi } from 'vitest'
import {
mountDefault,
searchSubmit,
selectTag,
selectWithProps,
} from '../helpers'
import VueSelect from '../../src/components/Select'
} from '@tests/helpers.js'
import VueSelect from '@/components/Select.vue'
describe('When Tagging Is Enabled', () => {
it('can determine if a given option string already exists', () => {
@@ -146,7 +147,7 @@ describe('When Tagging Is Enabled', () => {
})
it('should select an existing option if the search string matches a string from options', async () => {
let two = 'two'
const two = 'two'
const Select = selectWithProps({
taggable: true,
multiple: true,
@@ -159,7 +160,7 @@ describe('When Tagging Is Enabled', () => {
})
it('should select an existing option if the search string matches an objects label from options', async () => {
let two = { label: 'two' }
const two = { label: 'two' }
const Select = selectWithProps({
taggable: true,
options: [{ label: 'one' }, two],
@@ -170,7 +171,7 @@ describe('When Tagging Is Enabled', () => {
})
it('should select an existing option if the search string matches an objects label from options when filter-options is false', async () => {
let two = { label: 'two' }
const two = { label: 'two' }
const Select = selectWithProps({
taggable: true,
filterable: false,
@@ -222,7 +223,7 @@ describe('When Tagging Is Enabled', () => {
})
it('should not allow duplicate tags when using object options', async () => {
const spy = jest.spyOn(VueSelect.methods, 'select')
const spy = vi.spyOn(VueSelect.methods, 'select')
const Select = selectWithProps({
taggable: true,
multiple: true,
+3 -4
View File
@@ -1,8 +1,7 @@
import { it, describe, expect } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import VueSelect from '../../src/components/Select'
import { mountDefault, mountWithoutTestUtils } from '../helpers'
import typeAheadMixin from '../../src/mixins/typeAheadPointer'
import Vue from 'vue'
import VueSelect from '@/components/Select.vue'
import { mountDefault } from '@tests/helpers.js'
describe('Moving the Typeahead Pointer', () => {
it('should set the pointer to zero when the filteredOptions watcher is called', async () => {
+2 -1
View File
@@ -1,4 +1,5 @@
import sortAndStringify from '../../../src/utility/sortAndStringify'
import { test, expect } from 'vitest'
import sortAndStringify from '@/utility/sortAndStringify'
test('it will stringify an object', () => {
expect(sortAndStringify({ hello: 'world' })).toEqual('{"hello":"world"}')
+2 -1
View File
@@ -1,4 +1,5 @@
import uniqueId from '../../../src/utility/uniqueId'
import { test, expect } from 'vitest'
import uniqueId from '@/utility/uniqueId'
test('it generates a unique number', () => {
expect(uniqueId()).not.toEqual(uniqueId())
+13
View File
@@ -0,0 +1,13 @@
{
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["tests"],
"compilerOptions": {
"composite": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@tests/*": ["./tests/*"]
}
}
}
+14
View File
@@ -0,0 +1,14 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.vite-config.json"
},
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.vitest.json"
}
]
}
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "@vue/tsconfig/tsconfig.node.json",
"include": ["vite.config.*"],
"compilerOptions": {
"composite": true,
"types": ["node", "vitest"]
}
}
+9
View File
@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.app.json",
"exclude": [],
"compilerOptions": {
"composite": true,
"lib": [],
"types": ["node", "jsdom"]
}
}
+42
View File
@@ -0,0 +1,42 @@
import { resolve } from 'path'
import { fileURLToPath, URL } from 'url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
publicDir: false,
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
'@tests': fileURLToPath(new URL('./tests', import.meta.url)),
},
},
build: {
target: 'es2015',
lib: {
entry: resolve(__dirname, 'src/index.js'),
name: 'vue-select',
fileName: (format) => `vue-select.${format}.js`,
},
rollupOptions: {
external: ['vue'],
output: {
globals: { vue: 'Vue' },
assetFileNames(chunk): string {
if (chunk.name === 'style.css') {
return 'vue-select.css'
}
return chunk.name || ''
},
},
},
},
test: {
coverage: {
reporter: ['lcov'],
},
},
})
+3060 -9580
View File
File diff suppressed because it is too large Load Diff