test: migrate tests to vitest (wip)

This commit is contained in:
Evan You 2022-05-19 18:21:26 +08:00
parent fe13212456
commit 972d8066d7
15 changed files with 612 additions and 447 deletions

View File

@ -89,6 +89,7 @@
"hash-sum": "^2.0.0",
"he": "^1.2.0",
"http-server": "^14.1.0",
"jsdom": "^19.0.0",
"lint-staged": "^12.4.1",
"lodash": "^4.17.21",
"lodash.template": "^4.4.0",

View File

@ -23,6 +23,7 @@ specifiers:
hash-sum: ^2.0.0
he: ^1.2.0
http-server: ^14.1.0
jsdom: ^19.0.0
lint-staged: ^12.4.1
lodash: ^4.17.21
lodash.template: ^4.4.0
@ -66,6 +67,7 @@ devDependencies:
hash-sum: 2.0.0
he: 1.2.0
http-server: 14.1.0
jsdom: 19.0.0
lint-staged: 12.4.1
lodash: 4.17.21
lodash.template: 4.5.0
@ -81,7 +83,7 @@ devDependencies:
ts-node: 10.7.0_3smuweqyuzdazdnyhhezld6mfa
tslib: 2.4.0
typescript: 4.6.4
vitest: 0.12.6
vitest: 0.12.6_jsdom@19.0.0
weex-js-runtime: 0.23.7
weex-styler: 0.3.1
yorkie: 2.0.0
@ -308,6 +310,11 @@ packages:
picomatch: 2.3.1
dev: true
/@tootallnate/once/2.0.0:
resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
engines: {node: '>= 10'}
dev: true
/@tsconfig/node10/1.0.8:
resolution: {integrity: sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==}
dev: true
@ -515,6 +522,17 @@ packages:
through: 2.3.8
dev: true
/abab/2.0.6:
resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
dev: true
/acorn-globals/6.0.0:
resolution: {integrity: sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==}
dependencies:
acorn: 7.4.1
acorn-walk: 7.2.0
dev: true
/acorn-jsx/5.3.2_acorn@8.7.1:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
@ -523,11 +541,22 @@ packages:
acorn: 8.7.1
dev: true
/acorn-walk/7.2.0:
resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==}
engines: {node: '>=0.4.0'}
dev: true
/acorn-walk/8.2.0:
resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==}
engines: {node: '>=0.4.0'}
dev: true
/acorn/7.4.1:
resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: true
/acorn/8.7.1:
resolution: {integrity: sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==}
engines: {node: '>=0.4.0'}
@ -538,6 +567,15 @@ packages:
resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==}
dev: true
/agent-base/6.0.2:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
engines: {node: '>= 6.0.0'}
dependencies:
debug: 4.3.4
transitivePeerDependencies:
- supports-color
dev: true
/aggregate-error/3.1.0:
resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
engines: {node: '>=8'}
@ -643,6 +681,10 @@ packages:
lodash: 4.17.21
dev: true
/asynckit/0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: true
/atob/2.1.2:
resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==}
engines: {node: '>= 4.5.0'}
@ -674,6 +716,10 @@ packages:
fill-range: 7.0.1
dev: true
/browser-process-hrtime/1.0.0:
resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==}
dev: true
/buffer-from/1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: true
@ -828,6 +874,13 @@ packages:
resolution: {integrity: sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==}
dev: true
/combined-stream/1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
dependencies:
delayed-stream: 1.0.0
dev: true
/commander/2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
dev: true
@ -1094,6 +1147,21 @@ packages:
urix: 0.1.0
dev: true
/cssom/0.3.8:
resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==}
dev: true
/cssom/0.5.0:
resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==}
dev: true
/cssstyle/2.3.0:
resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==}
engines: {node: '>=8'}
dependencies:
cssom: 0.3.8
dev: true
/cz-conventional-changelog/3.2.0:
resolution: {integrity: sha512-yAYxeGpVi27hqIilG1nh4A9Bnx4J3Ov+eXy4koL3drrR+IO9GaWPsKjik20ht608Asqi8TQPf0mczhEeyAtMzg==}
engines: {node: '>= 10'}
@ -1133,6 +1201,15 @@ packages:
engines: {node: '>=8'}
dev: true
/data-urls/3.0.2:
resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==}
engines: {node: '>=12'}
dependencies:
abab: 2.0.6
whatwg-mimetype: 3.0.0
whatwg-url: 11.0.0
dev: true
/dateformat/3.0.3:
resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==}
dev: true
@ -1190,6 +1267,10 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/decimal.js/10.3.1:
resolution: {integrity: sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==}
dev: true
/decode-uri-component/0.2.0:
resolution: {integrity: sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=}
engines: {node: '>=0.10'}
@ -1215,6 +1296,11 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/delayed-stream/1.0.0:
resolution: {integrity: sha1-3zrhmayt+31ECqrgsp4icrJOxhk=}
engines: {node: '>=0.4.0'}
dev: true
/detect-file/1.0.0:
resolution: {integrity: sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=}
engines: {node: '>=0.10.0'}
@ -1244,6 +1330,13 @@ packages:
esutils: 2.0.3
dev: true
/domexception/4.0.0:
resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==}
engines: {node: '>=12'}
dependencies:
webidl-conversions: 7.0.0
dev: true
/dot-prop/5.3.0:
resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==}
engines: {node: '>=8'}
@ -1810,6 +1903,15 @@ packages:
optional: true
dev: true
/form-data/4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
dev: true
/fs-extra/10.1.0:
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
engines: {node: '>=12'}
@ -2080,6 +2182,17 @@ packages:
whatwg-encoding: 2.0.0
dev: true
/http-proxy-agent/5.0.0:
resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==}
engines: {node: '>= 6'}
dependencies:
'@tootallnate/once': 2.0.0
agent-base: 6.0.2
debug: 4.3.4
transitivePeerDependencies:
- supports-color
dev: true
/http-proxy/1.18.1:
resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==}
engines: {node: '>=8.0.0'}
@ -2114,6 +2227,16 @@ packages:
- supports-color
dev: true
/https-proxy-agent/5.0.1:
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
engines: {node: '>= 6'}
dependencies:
agent-base: 6.0.2
debug: 4.3.4
transitivePeerDependencies:
- supports-color
dev: true
/human-signals/2.1.0:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'}
@ -2265,6 +2388,10 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/is-potential-custom-element-name/1.0.1:
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
dev: true
/is-reference/1.2.1:
resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
dependencies:
@ -2316,6 +2443,48 @@ packages:
argparse: 2.0.1
dev: true
/jsdom/19.0.0:
resolution: {integrity: sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A==}
engines: {node: '>=12'}
peerDependencies:
canvas: ^2.5.0
peerDependenciesMeta:
canvas:
optional: true
dependencies:
abab: 2.0.6
acorn: 8.7.1
acorn-globals: 6.0.0
cssom: 0.5.0
cssstyle: 2.3.0
data-urls: 3.0.2
decimal.js: 10.3.1
domexception: 4.0.0
escodegen: 2.0.0
form-data: 4.0.0
html-encoding-sniffer: 3.0.0
http-proxy-agent: 5.0.0
https-proxy-agent: 5.0.1
is-potential-custom-element-name: 1.0.1
nwsapi: 2.2.0
parse5: 6.0.1
saxes: 5.0.1
symbol-tree: 3.2.4
tough-cookie: 4.0.0
w3c-hr-time: 1.0.2
w3c-xmlserializer: 3.0.0
webidl-conversions: 7.0.0
whatwg-encoding: 2.0.0
whatwg-mimetype: 3.0.0
whatwg-url: 10.0.0
ws: 8.6.0
xml-name-validator: 4.0.0
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
dev: true
/json-parse-better-errors/1.0.2:
resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==}
dev: true
@ -2610,6 +2779,18 @@ packages:
picomatch: 2.3.1
dev: true
/mime-db/1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
dev: true
/mime-types/2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
dependencies:
mime-db: 1.52.0
dev: true
/mime/1.6.0:
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
engines: {node: '>=4'}
@ -2735,6 +2916,10 @@ packages:
path-key: 3.1.1
dev: true
/nwsapi/2.2.0:
resolution: {integrity: sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==}
dev: true
/object-inspect/1.12.0:
resolution: {integrity: sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==}
dev: true
@ -2887,6 +3072,10 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/parse5/6.0.1:
resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==}
dev: true
/path-exists/3.0.0:
resolution: {integrity: sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=}
engines: {node: '>=4'}
@ -3021,6 +3210,10 @@ packages:
resolution: {integrity: sha1-8FKijacOYYkX7wqKw0wa5aaChrM=}
dev: true
/psl/1.8.0:
resolution: {integrity: sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==}
dev: true
/punycode/2.1.1:
resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
engines: {node: '>=6'}
@ -3272,6 +3465,13 @@ packages:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
dev: true
/saxes/5.0.1:
resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==}
engines: {node: '>=10'}
dependencies:
xmlchars: 2.2.0
dev: true
/secure-compare/3.0.1:
resolution: {integrity: sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=}
dev: true
@ -3599,6 +3799,10 @@ packages:
engines: {node: '>= 0.4'}
dev: true
/symbol-tree/3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
dev: true
/terser/5.13.1:
resolution: {integrity: sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==}
engines: {node: '>=10'}
@ -3660,12 +3864,28 @@ packages:
is-number: 7.0.0
dev: true
/tough-cookie/4.0.0:
resolution: {integrity: sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==}
engines: {node: '>=6'}
dependencies:
psl: 1.8.0
punycode: 2.1.1
universalify: 0.1.2
dev: true
/tr46/1.0.1:
resolution: {integrity: sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=}
dependencies:
punycode: 2.1.1
dev: true
/tr46/3.0.0:
resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==}
engines: {node: '>=12'}
dependencies:
punycode: 2.1.1
dev: true
/trim-newlines/3.0.1:
resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
engines: {node: '>=8'}
@ -3862,7 +4082,7 @@ packages:
fsevents: 2.3.2
dev: true
/vitest/0.12.6:
/vitest/0.12.6_jsdom@19.0.0:
resolution: {integrity: sha512-YWbCTv0XKBuBw5YtuW/iufuguoi8QhGpYyi2g57Oo7akpscMkkWTAaZGgY0ux1oJJtO/pc/8GFt0EF32WFBUUQ==}
engines: {node: '>=v14.16.0'}
hasBin: true
@ -3884,6 +4104,7 @@ packages:
'@types/chai': 4.3.1
'@types/chai-subset': 1.3.3
chai: 4.3.6
jsdom: 19.0.0
local-pkg: 0.4.1
tinypool: 0.1.3
tinyspy: 0.3.2
@ -3894,10 +4115,28 @@ packages:
- stylus
dev: true
/w3c-hr-time/1.0.2:
resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}
dependencies:
browser-process-hrtime: 1.0.0
dev: true
/w3c-xmlserializer/3.0.0:
resolution: {integrity: sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==}
engines: {node: '>=12'}
dependencies:
xml-name-validator: 4.0.0
dev: true
/webidl-conversions/4.0.2:
resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
dev: true
/webidl-conversions/7.0.0:
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
engines: {node: '>=12'}
dev: true
/weex-js-runtime/0.23.7:
resolution: {integrity: sha512-3BFd5GXTo0X/GWh0KjzXDpIcPJuSwYuc9fE9llgez35IfVHs/nUmfkFBjifzxOJS2YLhtKf0Cy8eTQ00CJDWZA==}
engines: {node: '>=4'}
@ -3916,6 +4155,27 @@ packages:
iconv-lite: 0.6.3
dev: true
/whatwg-mimetype/3.0.0:
resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
engines: {node: '>=12'}
dev: true
/whatwg-url/10.0.0:
resolution: {integrity: sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==}
engines: {node: '>=12'}
dependencies:
tr46: 3.0.0
webidl-conversions: 7.0.0
dev: true
/whatwg-url/11.0.0:
resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==}
engines: {node: '>=12'}
dependencies:
tr46: 3.0.0
webidl-conversions: 7.0.0
dev: true
/whatwg-url/7.1.0:
resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==}
dependencies:
@ -3970,6 +4230,28 @@ packages:
resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=}
dev: true
/ws/8.6.0:
resolution: {integrity: sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: ^5.0.2
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
dev: true
/xml-name-validator/4.0.0:
resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
engines: {node: '>=12'}
dev: true
/xmlchars/2.2.0:
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
dev: true
/xtend/4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}

View File

@ -1,75 +0,0 @@
function noop () {}
if (typeof console === 'undefined') {
// @ts-expect-error
window.console = {
warn: noop,
error: noop
}
}
// avoid info messages during test
console.info = noop
let asserted
function createCompareFn (spy) {
const hasWarned = msg => {
let count = spy.calls.count()
let args
while (count--) {
args = spy.calls.argsFor(count)
if (args.some(containsMsg)) {
return true
}
}
function containsMsg (arg) {
return arg.toString().indexOf(msg) > -1
}
}
return {
compare: msg => {
asserted = asserted.concat(msg)
const warned = Array.isArray(msg)
? msg.some(hasWarned)
: hasWarned(msg)
return {
pass: warned,
message: warned
? 'Expected message "' + msg + '" not to have been warned'
: 'Expected message "' + msg + '" to have been warned'
}
}
}
}
// define custom matcher for warnings
beforeEach(() => {
asserted = []
spyOn(console, 'warn')
spyOn(console, 'error')
jasmine.addMatchers({
toHaveBeenWarned: () =>
// @ts-expect-error
createCompareFn(console.error),
toHaveBeenTipped: () =>
// @ts-expect-error
createCompareFn(console.warn)
})
})
afterEach(done => {
const warned = msg => asserted.some(assertedMsg => msg.toString().indexOf(assertedMsg) > -1)
let count = console.error.calls.count()
let args
while (count--) {
args = console.error.calls.argsFor(count)
if (!warned(args[0])) {
done.fail(`Unexpected console.error message: ${args[0]}`)
return
}
}
done()
})

View File

@ -1,44 +1,57 @@
import Vue from 'vue'
describe('Component async', () => {
function wait(): [() => void, Promise<void>] {
let done
const p = new Promise<void>((resolve, reject) => {
done = resolve
done.fail = reject
})
return [done, p]
}
const oldSetTimeout = window.setTimeout;
const oldClearTimeout = window.clearTimeout;
describe('Component async', () => {
const oldSetTimeout = setTimeout
const oldClearTimeout = clearTimeout
// will contain pending timeouts set during the test iteration
// will contain the id of the timeout as the key, and the millisecond timeout as the value
// this helps to identify the timeout that is still pending
let timeoutsPending = {};
beforeEach(function () {
// reset the timeouts for this iteration
timeoutsPending = {};
let timeoutsPending = {}
beforeAll(function () {
// @ts-expect-error
global.setTimeout = function(func, delay) {
const id = oldSetTimeout(function() {
delete timeoutsPending[id];
func();
}, delay);
timeoutsPending[id] = delay;
global.setTimeout = function (func, delay) {
const id = oldSetTimeout(function () {
delete timeoutsPending[id]
func()
}, delay) as any
timeoutsPending[id] = delay
return id
};
}
window.clearTimeout = function(id) {
oldClearTimeout(id);
delete timeoutsPending[id];
};
global.clearTimeout = function (id) {
oldClearTimeout(id)
delete timeoutsPending[id]
}
})
afterEach(function () {
window.setTimeout = oldSetTimeout;
window.clearTimeout = oldClearTimeout;
afterAll(function () {
global.setTimeout = oldSetTimeout
global.clearTimeout = oldClearTimeout
})
beforeEach(() => {
// reset the timeouts for this iteration
timeoutsPending = {}
})
afterEach(() => {
// after the test is complete no timeouts that have been set up during the test should still be active
// compare stringified JSON for better error message containing ID and millisecond timeout
expect(JSON.stringify(timeoutsPending)).toEqual(JSON.stringify({}))
})
it('normal', done => {
it('normal', () => {
const vm = new Vue({
template: '<div><test></test></div>',
components: {
@ -55,14 +68,17 @@ describe('Component async', () => {
}).$mount()
expect(vm.$el.innerHTML).toBe('<!---->')
expect(vm.$children.length).toBe(0)
function next () {
const [done, p] = wait()
function next() {
expect(vm.$el.innerHTML).toBe('<div>hi</div>')
expect(vm.$children.length).toBe(1)
done()
}
return p
})
it('resolve ES module default', done => {
it('resolve ES module default', () => {
const vm = new Vue({
template: '<div><test></test></div>',
components: {
@ -82,18 +98,21 @@ describe('Component async', () => {
}).$mount()
expect(vm.$el.innerHTML).toBe('<!---->')
expect(vm.$children.length).toBe(0)
function next () {
const [done, p] = wait()
function next() {
expect(vm.$el.innerHTML).toBe('<div>hi</div>')
expect(vm.$children.length).toBe(1)
done()
}
return p
})
it('as root', done => {
it('as root', () => {
const vm = new Vue({
template: '<test></test>',
components: {
test: resolve => {
test: (resolve) => {
setTimeout(() => {
resolve({
template: '<div>hi</div>'
@ -106,22 +125,25 @@ describe('Component async', () => {
}).$mount()
expect(vm.$el.nodeType).toBe(8)
expect(vm.$children.length).toBe(0)
function next () {
const [done, p] = wait()
function next() {
expect(vm.$el.nodeType).toBe(1)
expect(vm.$el.outerHTML).toBe('<div>hi</div>')
expect(vm.$children.length).toBe(1)
done()
}
return p
})
it('dynamic', done => {
it('dynamic', () => {
const vm = new Vue({
template: '<component :is="view"></component>',
data: {
view: 'view-a'
},
components: {
'view-a': resolve => {
'view-a': (resolve) => {
setTimeout(() => {
resolve({
template: '<div>A</div>'
@ -129,7 +151,7 @@ describe('Component async', () => {
Vue.nextTick(step1)
}, 0)
},
'view-b': resolve => {
'view-b': (resolve) => {
setTimeout(() => {
resolve({
template: '<p>B</p>'
@ -140,7 +162,7 @@ describe('Component async', () => {
}
}).$mount()
let aCalled = false
function step1 () {
function step1() {
// ensure A is resolved only once
expect(aCalled).toBe(false)
aCalled = true
@ -148,15 +170,18 @@ describe('Component async', () => {
expect(vm.$el.textContent).toBe('A')
vm.view = 'view-b'
}
function step2 () {
const [done, p] = wait()
function step2() {
expect(vm.$el.tagName).toBe('P')
expect(vm.$el.textContent).toBe('B')
vm.view = 'view-a'
global.waitForUpdate(function () {
waitForUpdate(() => {
expect(vm.$el.tagName).toBe('DIV')
expect(vm.$el.textContent).toBe('A')
}).then(done)
}
return p
})
it('warn reject', () => {
@ -171,14 +196,14 @@ describe('Component async', () => {
expect('Reason: nooooo').toHaveBeenWarned()
})
it('with v-for', done => {
it('with v-for', () => {
const vm = new Vue({
template: '<div><test v-for="n in list" :key="n" :n="n"></test></div>',
data: {
list: [1, 2, 3]
},
components: {
test: resolve => {
test: (resolve) => {
setTimeout(() => {
resolve({
props: ['n'],
@ -189,18 +214,20 @@ describe('Component async', () => {
}
}
}).$mount()
function next () {
const [done, p] = wait()
function next() {
expect(vm.$el.innerHTML).toBe('<div>1</div><div>2</div><div>3</div>')
done()
}
return p
})
it('returning Promise', done => {
it('returning Promise', () => {
const vm = new Vue({
template: '<div><test></test></div>',
components: {
test: () => {
return new Promise(resolve => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
template: '<div>hi</div>'
@ -216,20 +243,23 @@ describe('Component async', () => {
}).$mount()
expect(vm.$el.innerHTML).toBe('<!---->')
expect(vm.$children.length).toBe(0)
function next () {
const [done, p] = wait()
function next() {
expect(vm.$el.innerHTML).toBe('<div>hi</div>')
expect(vm.$children.length).toBe(1)
done()
}
return p
})
describe('loading/error/timeout', () => {
it('with loading component', done => {
it('with loading component', () => {
const vm = new Vue({
template: `<div><test/></div>`,
components: {
test: () => ({
component: new Promise(resolve => {
component: new Promise((resolve) => {
setTimeout(() => {
resolve({ template: '<div>hi</div>' })
// wait for promise resolve and then parent update
@ -254,19 +284,21 @@ describe('Component async', () => {
})
}, 1)
function next () {
const [done, p] = wait()
function next() {
expect(loadingAsserted).toBe(true)
expect(vm.$el.textContent).toBe('hi')
done()
}
return p
})
it('with loading component (0 delay)', done => {
it('with loading component (0 delay)', () => {
const vm = new Vue({
template: `<div><test/></div>`,
components: {
test: () => ({
component: new Promise(resolve => {
component: new Promise((resolve) => {
setTimeout(() => {
resolve({ template: '<div>hi</div>' })
// wait for promise resolve and then parent update
@ -283,13 +315,15 @@ describe('Component async', () => {
expect(vm.$el.textContent).toBe('loading')
function next () {
const [done, p] = wait()
function next() {
expect(vm.$el.textContent).toBe('hi')
done()
}
return p
})
it('with error component', done => {
it('with error component', () => {
const vm = new Vue({
template: `<div><test/></div>`,
components: {
@ -312,14 +346,16 @@ describe('Component async', () => {
expect(vm.$el.textContent).toBe('loading')
function next () {
const [done, p] = wait()
function next() {
expect(`Failed to resolve async component`).toHaveBeenWarned()
expect(vm.$el.textContent).toBe('error')
done()
}
return p
})
it('with error component + timeout', done => {
it('with error component + timeout', () => {
const vm = new Vue({
template: `<div><test/></div>`,
components: {
@ -350,13 +386,15 @@ describe('Component async', () => {
})
}, 1)
function next () {
const [done, p] = wait()
function next() {
expect(vm.$el.textContent).toBe('error') // late resolve ignored
done()
}
return p
})
it('should not trigger timeout if resolved', done => {
it('should not trigger timeout if resolved', () => {
const vm = new Vue({
template: `<div><test/></div>`,
components: {
@ -372,14 +410,16 @@ describe('Component async', () => {
}
}).$mount()
const [done, p] = wait()
setTimeout(() => {
expect(vm.$el.textContent).toBe('hi')
expect(`Failed to resolve async component`).not.toHaveBeenWarned()
done()
}, 50)
return p
})
it('should not have running timeout/loading if resolved', done => {
it('should not have running timeout/loading if resolved', () => {
const vm = new Vue({
template: `<div><test/></div>`,
components: {
@ -400,15 +440,17 @@ describe('Component async', () => {
}
}).$mount()
function next () {
const [done, p] = wait()
function next() {
expect(vm.$el.textContent).toBe('hi')
// the afterEach() will ensure that the timeouts for delay and timeout have been cleared
done()
}
return p
})
// #7107
it(`should work when resolving sync in sibling component's mounted hook`, done => {
it(`should work when resolving sync in sibling component's mounted hook`, () => {
let resolveTwo
const vm = new Vue({
@ -416,11 +458,11 @@ describe('Component async', () => {
components: {
one: {
template: `<div>one</div>`,
mounted () {
mounted() {
resolveTwo()
}
},
two: resolve => {
two: (resolve) => {
resolveTwo = () => {
resolve({
template: `<div>two</div>`
@ -431,9 +473,12 @@ describe('Component async', () => {
}).$mount()
expect(vm.$el.textContent).toBe('one ')
global.waitForUpdate(() => {
const [done, p] = wait()
waitForUpdate(() => {
expect(vm.$el.textContent).toBe('one two')
}).then(done)
return p
})
})
})

17
test/unit/global.d.ts vendored
View File

@ -6,14 +6,11 @@ declare function createTextVNode(
arg?: any
): any;
declare namespace jasmine {
interface Matchers<T> {
toHaveBeenWarned(): void;
toHaveBeenTipped(): void;
// vitest extends jest namespace so we can just extend jest.Matchers
declare namespace jest {
interface Matchers<R, T> {
toHaveBeenWarned(): R
toHaveBeenWarnedLast(): R
toHaveBeenWarnedTimes(n: number): R
}
interface ArrayLikeMatchers<T> {
toHaveBeenWarned(): void;
toHaveBeenTipped(): void;
}
}
}

View File

@ -1,10 +0,0 @@
// NOTE: do not convert this to typescript (or karma will be unhappy)
require('es6-promise/auto')
// import all helpers
const helpersContext = require.context('../helpers', true)
helpersContext.keys().forEach(helpersContext)
// require all test files
const testsContext = require.context('./', true, /\.spec$/)
testsContext.keys().forEach(testsContext)

View File

@ -1,112 +0,0 @@
const alias = require('../../scripts/alias')
const featureFlags = require('../../scripts/feature-flags')
const webpack = require('webpack')
const webpackConfig = {
mode: 'development',
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.tsx?$/,
exclude: /node_modules/,
// loader: 'ts-loader',
// loader: 'babel-loader!ts-loader',
use: ['babel-loader', 'ts-loader']
},
]
},
resolve: {
alias: alias,
extensions: ['.tsx', '.ts', '.js'],
fallback: {
'stream': require.resolve("stream-browserify")
}
},
plugins: [
new webpack.DefinePlugin({
__WEEX__: false,
'process.env': {
TRANSITION_DURATION: process.env.CI ? 100 : 50,
TRANSITION_BUFFER: 10,
...featureFlags
}
})
],
devtool: 'inline-source-map'
}
// shared config for all unit tests
module.exports = {
frameworks: ['jasmine', 'webpack', 'karma-typescript'],
files: [
'./index.js',
"../../src/**/*.ts" // *.tsx for React Jsx
],
preprocessors: {
'./index.js': ['webpack', 'sourcemap'],
"**/*.ts": ["karma-typescript", 'webpack', 'sourcemap'] // *.tsx for React Jsx
},
webpack: webpackConfig,
webpackMiddleware: {
noInfo: true
},
plugins: [
'karma-jasmine',
'karma-mocha-reporter',
'karma-sourcemap-loader',
'karma-webpack',
'karma-typescript'
],
karmaTypescriptConfig: {
// "compilerOptions": {
// "baseUrl": ".",
// "outDir": "dist",
// "sourceMap": true,
// "target": "ESNext",
// "module": "ESNext",
// "moduleResolution": "node",
// "strict": true,
// "allowJs": true,
// "noImplicitAny": false,
// "noImplicitThis": false,
// "noUnusedLocals": true,
// "experimentalDecorators": true,
// "resolveJsonModule": true,
// "esModuleInterop": true,
// "removeComments": false,
// "jsx": "preserve",
// "lib": ["esnext", "dom"],
// "types": [
// "node",
// "jasmine",
// "webpack-env"
// ],
// "paths": {
// "compiler/*": ["../../src/compiler/*"],
// "core/*": ["../../src/core/*"],
// "server/*": ["../../src/server/*"],
// "sfc/*": ["../../src/sfc/*"],
// "shared/*": ["../../src/shared/*"],
// "web/*": ["../../src/platforms/web/*"],
// "weex/*": ["../../src/platforms/weex/*"],
// "vue": ["../../src/platforms/web/entry-runtime-with-compiler"]
// }
// },
"include": ["./global.d.ts"],
// "exclude": ["flow", "node_modules", "packages", "types"]
// // bundlerOptions: {
// // transforms: [require("karma-typescript-es6-transform")()]
// // }
}
}

View File

@ -1,42 +0,0 @@
const base = require('./karma.base.config.ts')
process.env.CHROME_BIN = require('puppeteer').executablePath()
module.exports = function (config: any) {
const options = Object.assign(base, {
browsers: ['ChromeHeadlessCI'],
customLaunchers: {
'ChromeHeadlessCI': {
base: 'ChromeHeadless',
flags: ['--no-sandbox']
}
},
reporters: ['mocha', 'coverage', 'karma-typescript'],
coverageReporter: {
reporters: [
{ type: 'lcov', dir: '../../coverage', subdir: '.' },
{ type: 'text-summary', dir: '../../coverage', subdir: '.' }
]
},
singleRun: true,
plugins: base.plugins.concat([
'karma-coverage',
'karma-chrome-launcher'
])
})
// add babel-plugin-istanbul for code instrumentation
options.webpack.module.rules[0].options = {
plugins: [['istanbul', {
exclude: [
'test/',
'src/compiler/parser/html-parser.ts',
'src/core/instance/proxy.ts',
'src/sfc/deindent.ts',
'src/platforms/weex/'
]
}]]
}
config.set(options)
}

View File

@ -1,13 +0,0 @@
const base = require('./karma.base.config.ts')
process.env.CHROME_BIN = require('puppeteer').executablePath()
module.exports = function (config) {
config.set(Object.assign(base, {
browsers: ['ChromeHeadless'],
reporters: ['progress'],
plugins: base.plugins.concat([
'karma-chrome-launcher'
])
}))
}

View File

@ -1,106 +0,0 @@
const webpack = require('webpack')
const base = require('./karma.base.config.ts')
base.webpack.plugins = [
new webpack.DefinePlugin({
__WEEX__: false,
'process.env': {
NODE_ENV: '"development"',
// sauce lab vms are slow!
TRANSITION_DURATION: 500,
TRANSITION_BUFFER: 50
}
})
]
/**
* Having too many tests running concurrently on saucelabs
* causes timeouts and errors, so we have to run them in
* smaller batches.
*/
const batches = [
// the cool kids
{
sl_chrome: {
base: 'SauceLabs',
browserName: 'chrome',
platform: 'Windows 7'
},
sl_firefox: {
base: 'SauceLabs',
browserName: 'firefox'
},
sl_mac_safari: {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.10'
}
},
// ie family
{
sl_ie_9: {
base: 'SauceLabs',
browserName: 'internet explorer',
platform: 'Windows 7',
version: '9'
},
sl_ie_10: {
base: 'SauceLabs',
browserName: 'internet explorer',
platform: 'Windows 8',
version: '10'
},
sl_ie_11: {
base: 'SauceLabs',
browserName: 'internet explorer',
platform: 'Windows 8.1',
version: '11'
},
sl_edge: {
base: 'SauceLabs',
browserName: 'MicrosoftEdge',
platform: 'Windows 10'
}
},
// mobile
{
sl_ios_safari_9: {
base: 'SauceLabs',
browserName: 'iphone',
version: '10.3'
},
sl_android_6_0: {
base: 'SauceLabs',
browserName: 'android',
version: '6.0'
}
}
]
module.exports = function (config) {
const batch = batches[process.argv[4] || 0]
config.set(Object.assign(base, {
singleRun: true,
browsers: Object.keys(batch),
customLaunchers: batch,
reporters: process.env.CI
? ['dots', 'saucelabs'] // avoid spamming CI output
: ['progress', 'saucelabs'],
sauceLabs: {
testName: 'Vue.js unit tests',
recordScreenshots: false,
connectOptions: {
'no-ssl-bump-domains': 'all' // Ignore SSL error on Android emulator
},
build: process.env.CIRCLE_BUILD_NUM || process.env.SAUCE_BUILD_ID || Date.now()
},
// mobile emulators are really slow
captureTimeout: 300000,
browserNoActivityTimeout: 300000,
plugins: base.plugins.concat([
'karma-sauce-launcher'
])
}))
}

View File

@ -1,14 +0,0 @@
const base = require('./karma.base.config.ts')
module.exports = function (config) {
config.set(Object.assign(base, {
browsers: ['Chrome', 'Firefox', 'Safari'],
reporters: ['progress'],
singleRun: true,
plugins: base.plugins.concat([
'karma-chrome-launcher',
'karma-firefox-launcher',
'karma-safari-launcher'
])
}))
}

View File

@ -47,15 +47,15 @@ describe('Dep', () => {
})
it('should add itself to target', () => {
Dep.target = jasmine.createSpyObj('TARGET', ['addDep'])
Dep.target = { addDep: vi.fn() } as any
dep.depend()
expect(Dep.target.addDep).toHaveBeenCalledWith(dep)
expect(Dep.target!.addDep).toHaveBeenCalledWith(dep)
})
})
describe('notify()', () => {
it('should notify subs', () => {
dep.subs.push(jasmine.createSpyObj('SUB', ['update']))
dep.subs.push({ update: vi.fn() })
dep.notify()
expect(dep.subs[0].update).toHaveBeenCalled()
})

185
test/vitest.setup.ts Normal file
View File

@ -0,0 +1,185 @@
import { SpyInstance } from 'vitest'
expect.extend({
toHaveBeenWarned(received: string) {
asserted.add(received)
const passed = warn.mock.calls.some((args) => args[0].includes(received))
if (passed) {
return {
pass: true,
message: () => `expected "${received}" not to have been warned.`
}
} else {
const msgs = warn.mock.calls.map((args) => args[0]).join('\n - ')
return {
pass: false,
message: () =>
`expected "${received}" to have been warned` +
(msgs.length
? `.\n\nActual messages:\n\n - ${msgs}`
: ` but no warning was recorded.`)
}
}
},
toHaveBeenWarnedLast(received: string) {
asserted.add(received)
const passed =
warn.mock.calls[warn.mock.calls.length - 1][0].includes(received)
if (passed) {
return {
pass: true,
message: () => `expected "${received}" not to have been warned last.`
}
} else {
const msgs = warn.mock.calls.map((args) => args[0]).join('\n - ')
return {
pass: false,
message: () =>
`expected "${received}" to have been warned last.\n\nActual messages:\n\n - ${msgs}`
}
}
},
toHaveBeenWarnedTimes(received: string, n: number) {
asserted.add(received)
let found = 0
warn.mock.calls.forEach((args) => {
if (args[0].includes(received)) {
found++
}
})
if (found === n) {
return {
pass: true,
message: () => `expected "${received}" to have been warned ${n} times.`
}
} else {
return {
pass: false,
message: () =>
`expected "${received}" to have been warned ${n} times but got ${found}.`
}
}
}
})
let warn: SpyInstance
const asserted: Set<string> = new Set()
beforeEach(() => {
asserted.clear()
warn = vi.spyOn(console, 'error')
warn.mockImplementation(() => {})
})
afterEach(() => {
const assertedArray = Array.from(asserted)
const nonAssertedWarnings = warn.mock.calls
.map((args) => args[0])
.filter((received) => {
return !assertedArray.some((assertedMsg) => {
return received.includes(assertedMsg)
})
})
warn.mockRestore()
if (nonAssertedWarnings.length) {
throw new Error(
`test case threw unexpected warnings:\n - ${nonAssertedWarnings.join(
'\n - '
)}`
)
}
})
import Vue from 'vue'
// helper for async assertions.
// Use like this:
//
// vm.a = 123
// waitForUpdate(() => {
// expect(vm.$el.textContent).toBe('123')
// vm.a = 234
// })
// .then(() => {
// // more assertions...
// })
// .then(done)
interface Job extends Function {
wait?: boolean
fail?: (e: any) => void
}
global.waitForUpdate = (initialCb: Job) => {
let end
let reject
const queue: Job[] = initialCb ? [initialCb] : []
function shift() {
const job = queue.shift()
if (queue.length) {
let hasError = false
try {
job!.wait ? job!(shift) : job!()
} catch (e) {
hasError = true
if (reject) {
reject()
} else {
const done = queue[queue.length - 1]
if (done && done.fail) {
done.fail(e)
}
}
}
if (!hasError && !job!.wait) {
if (queue.length) {
Vue.nextTick(shift)
}
}
} else if (job && (job.fail || job === end)) {
job() // done
}
}
Vue.nextTick(() => {
if (!queue.length || (!end && !queue[queue.length - 1]!.fail)) {
throw new Error('waitForUpdate chain is missing .then(done)')
}
shift()
})
const chainer = {
then: (nextCb) => {
queue.push(nextCb)
return chainer
},
thenWaitFor: (wait) => {
if (typeof wait === 'number') {
wait = timeout(wait)
}
wait.wait = true
queue.push(wait)
return chainer
},
end: (endFn) => {
queue.push(endFn)
end = endFn
},
promise() {
return new Promise((resolve, rej) => {
end = resolve
reject = rej
})
}
}
return chainer
}
function timeout(n) {
return (next) => setTimeout(next, n)
}

View File

@ -3,7 +3,7 @@
"baseUrl": ".",
"outDir": "dist",
"sourceMap": true,
"target": "es5",
"target": "esnext",
"module": "ESNext",
"moduleResolution": "node",
"strict": true,
@ -19,7 +19,7 @@
"removeComments": false,
"jsx": "preserve",
"lib": ["esnext", "dom"],
"types": ["node"],
"types": ["node", "vitest/globals"],
"paths": {
"compiler/*": ["src/compiler/*"],
"core/*": ["src/core/*"],

27
vitest.config.ts Normal file
View File

@ -0,0 +1,27 @@
import { resolve as _resolve } from 'path'
import { defineConfig } from 'vitest/config'
const resolve = (p: string) => _resolve(__dirname, p)
export default defineConfig({
resolve: {
alias: {
compiler: resolve('src/compiler'),
core: resolve('src/core'),
server: resolve('src/server'),
sfc: resolve('src/sfc'),
shared: resolve('src/shared'),
web: resolve('src/platforms/web'),
weex: resolve('src/platforms/weex'),
vue: resolve('src/platforms/web/entry-runtime-with-compiler')
}
},
define: {
__WEEX__: false
},
test: {
globals: true,
environment: 'jsdom',
setupFiles: resolve('test/vitest.setup.ts')
}
})