@thednp/shorty 2.0.3 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +5 -5
  2. package/dist/shorty.cjs +1 -1
  3. package/dist/shorty.cjs.map +1 -1
  4. package/dist/shorty.d.ts +3 -3
  5. package/dist/shorty.js +1 -1
  6. package/dist/shorty.js.map +1 -1
  7. package/dist/shorty.mjs +14 -4
  8. package/dist/shorty.mjs.map +1 -1
  9. package/package.json +17 -15
  10. package/src/boolean/isApple.ts +1 -1
  11. package/src/boolean/isFirefox.ts +3 -1
  12. package/src/boolean/isMobile.ts +1 -1
  13. package/src/event/one.ts +1 -1
  14. package/src/get/getRectRelativeToOffsetParent.ts +1 -1
  15. package/src/misc/createCustomEvent.ts +5 -5
  16. package/src/misc/createElementNS.ts +1 -1
  17. package/src/misc/emulateAnimationEnd.ts +3 -2
  18. package/src/misc/emulateTransitionEnd.ts +2 -2
  19. package/src/selectors/closest.ts +5 -2
  20. package/test/att.test.ts +43 -0
  21. package/test/boolean.test.ts +30 -0
  22. package/test/class.test.ts +26 -0
  23. package/test/event.test.ts +39 -0
  24. package/{cypress/test.html → test/fixtures/getExampleDom.ts} +17 -32
  25. package/test/fixtures/style.css +18 -0
  26. package/test/get.test.ts +150 -0
  27. package/{cypress/e2e/is.cy.ts → test/is.test.ts} +77 -74
  28. package/test/misc.test.ts +352 -0
  29. package/test/selectors.test.ts +90 -0
  30. package/tsconfig.json +6 -1
  31. package/vitest.config-ui.ts +21 -0
  32. package/vitest.config.ts +20 -0
  33. package/cypress/e2e/att.cy.ts +0 -46
  34. package/cypress/e2e/boolean.cy.ts +0 -44
  35. package/cypress/e2e/class.cy.ts +0 -28
  36. package/cypress/e2e/event.cy.ts +0 -51
  37. package/cypress/e2e/get.cy.ts +0 -168
  38. package/cypress/e2e/misc.cy.ts +0 -354
  39. package/cypress/e2e/selectors.cy.ts +0 -85
  40. package/cypress/plugins/esbuild-istanbul.ts +0 -50
  41. package/cypress/plugins/tsCompile.ts +0 -34
  42. package/cypress/support/commands.ts +0 -37
  43. package/cypress/support/e2e.ts +0 -21
  44. package/cypress/support/index.js +0 -22
  45. package/cypress.config.ts +0 -30
  46. /package/{cypress → test}/fixtures/custom-elem.js +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thednp/shorty",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
4
4
  "description": "TypeScript shorties for the web",
5
5
  "source": "./src/index.ts",
6
6
  "main": "./dist/shorty.js",
@@ -32,25 +32,27 @@
32
32
  },
33
33
  "homepage": "https://github.com/thednp/shorty",
34
34
  "devDependencies": {
35
- "@bahmutov/cypress-esbuild-preprocessor": "^2.2.1",
36
- "@cypress/code-coverage": "^3.12.44",
37
- "@types/istanbul-lib-instrument": "^1.7.7",
38
- "@types/node": "^20.14.11",
35
+ "@types/node": "^20.16.5",
39
36
  "@typescript-eslint/eslint-plugin": "^5.62.0",
40
37
  "@typescript-eslint/parser": "^5.62.0",
41
- "cypress": "^13.13.1",
38
+ "@vitest/browser": "^2.1.1",
39
+ "@vitest/coverage-istanbul": "^2.1.1",
40
+ "@vitest/ui": "^2.1.1",
42
41
  "dts-bundle-generator": "^9.5.1",
43
- "eslint": "^8.57.0",
42
+ "eslint": "^8.57.1",
44
43
  "eslint-plugin-jsdoc": "^46.10.1",
45
44
  "eslint-plugin-prefer-arrow": "^1.2.3",
46
45
  "eslint-plugin-prettier": "^4.2.1",
46
+ "happy-dom": "^15.7.4",
47
47
  "istanbul-lib-coverage": "^3.2.2",
48
48
  "istanbul-lib-instrument": "^5.2.1",
49
49
  "nyc": "^15.1.0",
50
+ "playwright": "^1.47.1",
50
51
  "prettier": "^2.8.8",
51
- "rimraf": "^5.0.9",
52
- "typescript": "^5.5.3",
53
- "vite": "^5.3.4"
52
+ "rimraf": "^5.0.10",
53
+ "typescript": "^5.6.2",
54
+ "vite": "^5.4.6",
55
+ "vitest": "^2.1.1"
54
56
  },
55
57
  "engines": {
56
58
  "node": ">=16",
@@ -58,12 +60,12 @@
58
60
  },
59
61
  "scripts": {
60
62
  "pre-test": "pnpm clean-coverage",
61
- "badges": "npx -p dependency-version-badge update-badge typescript prettier cypress eslint vite",
62
- "test": "pnpm pre-test && npx cypress run",
63
- "clean-coverage": "rimraf coverage .nyc_output",
64
- "cypress": "pnpm pre-test && npx cypress open",
65
- "coverage:report": "nyc report --reporter=lcov --reporter=json --reporter=text --reporter=json-summary",
63
+ "badges": "npx -p dependency-version-badge update-badge typescript prettier eslint vitest vite",
64
+ "test": "pnpm pre-test && vitest --config vitest.config.ts",
65
+ "test-ui": "pnpm pre-test && vitest --config vitest.config-ui.ts",
66
+ "clean-coverage": "rm -rf coverage .nyc_output",
66
67
  "format": "prettier --write \"src/**/*.ts\"",
68
+ "lint": "pnpm lint:ts && pnpm check:ts",
67
69
  "lint:ts": "eslint -c .eslintrc.cjs --ext .ts src",
68
70
  "fix:ts": "eslint -c .eslintrc.cjs --ext .ts src --fix",
69
71
  "check:ts": "tsc -noEmit",
@@ -9,6 +9,6 @@ const appleBrands = /(iPhone|iPod|iPad)/;
9
9
  */
10
10
  const isApple: boolean = userAgentData
11
11
  ? userAgentData.brands.some((x: NavigatorUABrand) => appleBrands.test(x.brand))
12
- : /* istanbul ignore next */ appleBrands.test(userAgent);
12
+ : /* istanbul ignore next @preserve */ appleBrands.test(userAgent);
13
13
 
14
14
  export default isApple;
@@ -4,6 +4,8 @@ import userAgent from '../strings/userAgent';
4
4
  * A global boolean for Gecko browsers. When writing this file,
5
5
  * Gecko was not supporting `userAgentData`.
6
6
  */
7
- const isFirefox = userAgent ? userAgent.includes('Firefox') : /* istanbul ignore next */ false;
7
+ const isFirefox = userAgent
8
+ ? userAgent.includes('Firefox')
9
+ : /* istanbul ignore next @preserve */ false;
8
10
 
9
11
  export default isFirefox;
@@ -4,7 +4,7 @@ import userAgent from '../strings/userAgent';
4
4
  const mobileBrands = /iPhone|iPad|iPod|Android/i;
5
5
  let isMobileCheck = false;
6
6
 
7
- /* istanbul ignore else */
7
+ /* istanbul ignore else @preserve */
8
8
  if (userAgentData) {
9
9
  isMobileCheck = userAgentData.brands.some(x => mobileBrands.test(x.brand));
10
10
  } else {
package/src/event/one.ts CHANGED
@@ -14,7 +14,7 @@ const one = <T extends EventTarget, L = EventListener>(
14
14
  ) => {
15
15
  /** Wrap the listener for easy on -> off */
16
16
  const handlerWrapper: NativeEventHandler<T> = e => {
17
- /* istanbul ignore else */
17
+ /* istanbul ignore else @preserve */
18
18
  if (e.target === element || e.currentTarget === element) {
19
19
  (listener as NativeEventHandler<T>).apply(element, [e]);
20
20
  off(element, eventName, handlerWrapper, options);
@@ -22,7 +22,7 @@ const getRectRelativeToOffsetParent = (
22
22
  const rect = getBoundingClientRect(element, isParentAnElement && isScaledElement(offsetParent));
23
23
  const offsets = { x: 0, y: 0 };
24
24
 
25
- /* istanbul ignore next */
25
+ /* istanbul ignore else @preserve */
26
26
  if (isParentAnElement) {
27
27
  const offsetRect = getBoundingClientRect(offsetParent, true);
28
28
  offsets.x = offsetRect.x + offsetParent.clientLeft;
@@ -9,16 +9,16 @@ import ObjectAssign from './ObjectAssign';
9
9
  * @param config Event.options | Event.properties
10
10
  * @returns a new namespaced event
11
11
  */
12
- const createCustomEvent = <T extends OriginalEvent>(
12
+ const createCustomEvent = <O extends Record<string, unknown>, T extends OriginalEvent>(
13
13
  eventType: string,
14
- config?: CustomEventInit<any>,
14
+ config?: O,
15
15
  ): T => {
16
- const OriginalCustomEvent = new CustomEvent<any>(eventType, {
16
+ const OriginalCustomEvent = new CustomEvent<O>(eventType, {
17
17
  cancelable: true,
18
18
  bubbles: true,
19
- } as CustomEventInit<any>) as T;
19
+ }) as T;
20
20
 
21
- /* istanbul ignore else */
21
+ /* istanbul ignore else @preserve */
22
22
  if (isObject(config)) {
23
23
  ObjectAssign(OriginalCustomEvent, config);
24
24
  }
@@ -16,7 +16,7 @@ import isString from '../is/isString';
16
16
  * @param param `tagName` or object
17
17
  * @return a new `HTMLElement`
18
18
  */
19
- const createElementNS = <T extends HTMLElement>(
19
+ const createElementNS = <T extends Element = HTMLElement>(
20
20
  ns: string,
21
21
  param?: string | Partial<T>,
22
22
  ): T | undefined => {
@@ -19,7 +19,7 @@ const emulateAnimationEnd = (element: HTMLElement, handler: EventListener): void
19
19
  if (duration) {
20
20
  /** Wrap the handler in on -> off callback */
21
21
  const animationEndWrapper = (e: Event): void => {
22
- /* istanbul ignore else */
22
+ /* istanbul ignore else @preserve */
23
23
  if (e.target === element) {
24
24
  handler.apply(element, [e]);
25
25
  element.removeEventListener(animationEndEvent, animationEndWrapper);
@@ -28,10 +28,11 @@ const emulateAnimationEnd = (element: HTMLElement, handler: EventListener): void
28
28
  };
29
29
  element.addEventListener(animationEndEvent, animationEndWrapper);
30
30
  setTimeout(() => {
31
- /* istanbul ignore next */
31
+ /* istanbul ignore next @preserve */
32
32
  if (!called) dispatchEvent(element, endEvent);
33
33
  }, duration + delay + 17);
34
34
  } else {
35
+ /* istanbul ignore next @preserve */
35
36
  handler.apply(element, [endEvent]);
36
37
  }
37
38
  };
@@ -19,7 +19,7 @@ const emulateTransitionEnd = (element: HTMLElement, handler: EventListener): voi
19
19
  if (duration) {
20
20
  /** Wrap the handler in on -> off callback */
21
21
  const transitionEndWrapper = (e: Event): void => {
22
- /* istanbul ignore else */
22
+ /* istanbul ignore else @preserve */
23
23
  if (e.target === element) {
24
24
  handler.apply(element, [e]);
25
25
  element.removeEventListener(transitionEndEvent, transitionEndWrapper);
@@ -28,7 +28,7 @@ const emulateTransitionEnd = (element: HTMLElement, handler: EventListener): voi
28
28
  };
29
29
  element.addEventListener(transitionEndEvent, transitionEndWrapper);
30
30
  setTimeout(() => {
31
- /* istanbul ignore next */
31
+ /* istanbul ignore next @preserve */
32
32
  if (!called) dispatchEvent(element, endEvent);
33
33
  }, duration + delay + 17);
34
34
  } else {
@@ -9,11 +9,14 @@
9
9
  * @param selector the selector name
10
10
  * @return the query result
11
11
  */
12
- const closest = (element: HTMLElement, selector: string): HTMLElement | null => {
12
+ const closest = <T extends Element = HTMLElement>(
13
+ element: T,
14
+ selector: string,
15
+ ): HTMLElement | null => {
13
16
  return element
14
17
  ? element.closest(selector) ||
15
18
  // break out of `ShadowRoot`
16
- closest((element.getRootNode() as HTMLElement & { host: HTMLElement }).host, selector)
19
+ closest((element.getRootNode() as ShadowRoot).host, selector)
17
20
  : null;
18
21
  };
19
22
 
@@ -0,0 +1,43 @@
1
+ import { expect, it, describe, afterEach } from 'vitest';
2
+ import { getExampleDOM } from './fixtures/getExampleDom';
3
+ import * as SHORTY from '../src/index';
4
+ import "./fixtures/style.css";
5
+
6
+ describe('Shorty Library Tests - ATT', () => {
7
+ const wrapper = document.createElement('div');
8
+ afterEach(async () => {
9
+ wrapper.innerHTML = '';
10
+ });
11
+
12
+ it('Test attr folder', () => {
13
+ const container = getExampleDOM();
14
+ wrapper.append(container);
15
+
16
+ const {
17
+ getAttribute,
18
+ setAttribute,
19
+ hasAttribute,
20
+ removeAttribute,
21
+ getAttributeNS,
22
+ setAttributeNS,
23
+ hasAttributeNS,
24
+ removeAttributeNS,
25
+ querySelector,
26
+ } = SHORTY;
27
+
28
+ const el = querySelector('.alert', container)!;
29
+ expect(getAttribute(el, 'class')).to.have.length.above(0);
30
+ setAttribute(el, 'data-att', 'momo');
31
+ expect(hasAttribute(el, 'data-att')).to.be.true;
32
+ removeAttribute(el, 'data-att');
33
+ expect(hasAttribute(el, 'data-att')).to.be.false;
34
+
35
+ const svg = querySelector('svg', container)!;
36
+ const ns = 'http://www.w3.org/2000/svg';
37
+ expect(hasAttributeNS(ns, svg, 'transform')).to.be.false;
38
+ setAttributeNS(ns, svg, 'transform', 'scale(0.99)');
39
+ expect(getAttributeNS(ns, svg, 'transform')).to.eq('scale(0.99)');
40
+ removeAttributeNS(ns, svg, 'transform');
41
+ expect(getAttributeNS(ns, svg, 'transform')).to.be.null;
42
+ });
43
+ });
@@ -0,0 +1,30 @@
1
+ import { expect, it, describe } from 'vitest';
2
+ import * as SHORTY from '../src/index';
3
+
4
+ describe('Shorty Library Tests - BOOL', () => {
5
+ it('Test boolean folder', () => {
6
+ const {
7
+ // these are impossible to test 100% of the branches
8
+ isApple,
9
+ isMobile,
10
+ isFirefox,
11
+ support3DTransform,
12
+ supportAnimation,
13
+ supportPassive,
14
+ supportTouch,
15
+ supportTransform,
16
+ supportTransition,
17
+ // querySelectorAll, getWindow
18
+ } = SHORTY;
19
+
20
+ expect(isApple, 'isApple').to.be.false;
21
+ expect(isMobile, 'isMobile').to.be.false;
22
+ expect(isFirefox, 'isFirefox').to.be.false;
23
+ expect(support3DTransform, 'support3DTransform').to.be.true;
24
+ expect(supportAnimation, 'supportAnimation').to.be.true;
25
+ expect(supportPassive, 'supportPassive').to.be.true;
26
+ expect(supportTouch, 'supportTouch').to.be.false;
27
+ expect(supportTransform, 'supportTransform').to.be.true;
28
+ expect(supportTransition, 'supportTransition').to.be.true;
29
+ });
30
+ });
@@ -0,0 +1,26 @@
1
+ import { expect, it, describe, beforeEach, vi, afterEach } from 'vitest';
2
+ import { getExampleDOM } from './fixtures/getExampleDom';
3
+ import * as SHORTY from '../src/index';
4
+ import "./fixtures/style.css";
5
+
6
+ describe('Shorty Library Tests - CLASS', () => {
7
+ const wrapper = document.createElement('div');
8
+ document.body.append(wrapper);
9
+ afterEach(async () => {
10
+ wrapper.innerHTML = '';
11
+ });
12
+
13
+ it('Test class folder', () => {
14
+ const { addClass, hasClass, removeClass, querySelector } = SHORTY;
15
+ const container = getExampleDOM();
16
+ wrapper.append(container);
17
+
18
+ const alert = querySelector('.alert', container);
19
+ if (!alert) return;
20
+
21
+ addClass(alert, 'to-be-removed');
22
+ expect(hasClass(alert, 'to-be-removed')).to.be.true;
23
+ removeClass(alert, 'show');
24
+ expect(hasClass(alert, 'show')).to.be.false;
25
+ });
26
+ });
@@ -0,0 +1,39 @@
1
+ import { expect, it, describe, afterEach, beforeEach, vi } from 'vitest';
2
+ import { getExampleDOM } from './fixtures/getExampleDom';
3
+ import * as SHORTY from '../src/index';
4
+ import "./fixtures/style.css";
5
+
6
+ describe('Shorty Library Tests - EVENT', () => {
7
+ const wrapper = document.createElement('div');
8
+ document.body.append(wrapper);
9
+ afterEach(async () => {
10
+ wrapper.innerHTML = '';
11
+ });
12
+
13
+ it('Test event folder', () => {
14
+ const {
15
+ // on, off are called by one
16
+ one,
17
+ querySelector,
18
+ } = SHORTY;
19
+ const container = getExampleDOM();
20
+ wrapper.append(container);
21
+
22
+ const el = querySelector('.alert', container);
23
+ const btn = querySelector('button', container);
24
+
25
+ if (!el || !btn) return;
26
+
27
+ one(el, 'click', function handle(e) {
28
+ el.innerText += 'click fired for ' + (e.currentTarget as HTMLElement).tagName;
29
+ expect(el.innerText).toContain('click fired for DIV')
30
+
31
+ });
32
+
33
+ one(btn, 'click', function handle(e) {
34
+ el.innerText += 'click fired for ' + (e.target as HTMLElement).tagName;
35
+ expect(el.innerText).toContain('click fired for BUTTON')
36
+ });
37
+ btn.click();
38
+ });
39
+ });
@@ -1,36 +1,17 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <title>BSN Testing Page</title>
6
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css">
7
- <style>
8
- @keyframes animate-me {
9
- 0% { opacity: 1; }
10
- 50% { opacity: 0; }
11
- 100% { opacity: 1; }
12
- }
13
- @keyframes animate-test {
14
- from { left: 0px; }
15
- to { left: 150px; }
16
- }
17
- .animate-test {
18
- animation-name: animate-test;
19
- animation-duration: 0.3s;
20
- animation-timing-function: ease-out;
21
- animation-delay: 0s;
22
- }
23
- </style>
24
- </head>
25
- <body class="container p-5">
26
- <h3>Shorty Examples</h3>
27
- <div id="alertDemo" class="alert alert-warning alert-dismissible fade show" data-cy="alert" data-bs-op1="false" data-bs-op2="true" data-bs-op3="10" data-bs-title="" role="alert">
28
- <button type="button" class="btn-close bg-none" data-bs-target="alertDemo" data-bs-dismiss="alert" aria-label="Close">
29
- <svg viewBox="0 0 16 16" class="align-top"><path name="x" d="M4.646 4.646a0.5 0.5 0 0 1 0.708 0L8 7.293l2.646 -2.647a0.5 0.5 0 0 1 0.708 0.708L8.707 8l2.647 2.646a0.5 0.5 0 0 1 -0.708 0.708L8 8.707l-2.646 2.647A0.5 0.5 0 0 1 4.646 10.646L7.293 8L4.646 5.354a0.5 0.5 0 0 1 0 -0.708z"></path></svg>
1
+ export const getExampleDOM = () => {
2
+ const div = document.createElement('div');
3
+ div.className = 'm-4';
4
+ const tempDocument = new DOMParser().parseFromString(`
5
+ <div id="alertDemo" class="alert alert-warning alert-dismissible fade show" data-bs-op1="false" data-bs-op2="true" data-bs-op3="10" data-bs-title="" role="alert">
6
+ <button role="button" type="button" class="btn-close bg-none" data-bs-target="alertDemo" data-bs-dismiss="alert" aria-label="Close">
7
+ <svg viewBox="0 0 16 16" class="align-top">
8
+ <title>Delete</title>
9
+ <path name="x" d="M4.646 4.646a0.5 0.5 0 0 1 0.708 0L8 7.293l2.646 -2.647a0.5 0.5 0 0 1 0.708 0.708L8.707 8l2.647 2.646a0.5 0.5 0 0 1 -0.708 0.708L8 8.707l-2.646 2.647A0.5 0.5 0 0 1 4.646 10.646L7.293 8L4.646 5.354a0.5 0.5 0 0 1 0 -0.708z"></path>
10
+ </svg>
30
11
  </button>
31
12
  <p><b>Holy guacamole!</b> Best check yo self, you're not looking too good.</p>
32
13
  <img src="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgODAgNDMiIHdpZHRoPSI4MCIgaGVpZ2h0PSI0MyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCiAgICAgICAgICAgICAgICAgIDxyZWN0IGZpbGw9IndoaXRlIiBzdHJva2U9IiNjY2MiIHN0cm9rZS13aWR0aD0iMSIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgcng9IjUiPjwvcmVjdD4NCiAgICAgICAgICAgICAgICAgIDx0ZXh0IGRpcmVjdGlvbj0ibHRyIiBmaWxsPSIjMzMzIiB4PSIyNSIgeT0iMjUiIGZvbnQtc2l6ZT0iMTQiPklNRzwvdGV4dD4NCiAgICAgICAgICAgICAgICA8L3N2Zz4=" alt="Image">
33
- </div>
14
+ </div>
34
15
  <table class="table">
35
16
  <thead>
36
17
  <tr>
@@ -59,5 +40,9 @@
59
40
  </tr>
60
41
  </tbody>
61
42
  </table>
62
- </body>
63
- </html>
43
+ `, 'text/html');
44
+ // console.log(tempDocument.body.children)
45
+ div.append(...tempDocument.body.children);
46
+
47
+ return div;
48
+ };