From 6e34314543c17eae3ea3d6f3a9d274deb5bde6cd Mon Sep 17 00:00:00 2001 From: Aelita Date: Fri, 1 Dec 2023 01:35:32 +1100 Subject: [PATCH] test: introducing 100% coverage tests fix(slide): fix some bugs find in test for slide animation --- package.json | 2 +- src/index.ts | 6 +- src/rules.ts | 34 +-- src/shortcuts.ts | 2 +- src/theme.ts | 2 +- src/utils.ts | 28 +- test/base.test.ts | 36 +++ test/data/index.ts | 9 + test/fade.test.ts | 142 ++++++++++ test/slide.test.ts | 616 +++++++++++++++++++++++++++++++++++++++++++ test/spin.test.ts | 621 ++++++++++++++++++++++++++++++++++++++++++++ test/utils/index.ts | 17 ++ test/zoom.test.ts | 290 +++++++++++++++++++++ tsconfig.json | 7 +- vitest.config.ts | 12 + 15 files changed, 1789 insertions(+), 35 deletions(-) create mode 100644 test/base.test.ts create mode 100644 test/data/index.ts create mode 100644 test/fade.test.ts create mode 100644 test/slide.test.ts create mode 100644 test/spin.test.ts create mode 100644 test/utils/index.ts create mode 100644 test/zoom.test.ts create mode 100644 vitest.config.ts diff --git a/package.json b/package.json index 5ba84ec..2cea1e2 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "typecheck": "tsc --noEmit", "lint": "eslint .", "test": "vitest", - "test:update": "vitest -u", + "test:update": "vitest run -u", "test:ci": "pnpm typecheck && pnpm build && pnpm lint && pnpm test", "docs:dev": "vitepress dev docs", "docs:build": "vitepress build docs", diff --git a/src/index.ts b/src/index.ts index 313d1cb..edaaf6b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ import { definePreset } from '@unocss/core' -import { rules } from './rules' -import { shortcuts } from './shortcuts' -import { theme } from './theme' +import { rules } from '@/rules' +import { shortcuts } from '@/shortcuts' +import { theme } from '@/theme' // This is for fixing the `rollup-plugin-dts` generating wrong import issue. diff --git a/src/rules.ts b/src/rules.ts index 0b0edbf..081860e 100644 --- a/src/rules.ts +++ b/src/rules.ts @@ -1,6 +1,6 @@ import { h } from '@unocss/preset-mini/utils' -import { CSS_VARIABLE_PREFIX } from './constants' -import { normalizeDirection } from './utils' +import { CSS_VARIABLE_PREFIX } from '@/constants' +import { handleSlide } from '@/utils' import type { Theme } from '@unocss/preset-mini' import type { Rule } from 'unocss' @@ -8,7 +8,7 @@ import type { Rule } from 'unocss' const DEFAULT_FADE_OPACITY = '0' const DEFAULT_ZOOM_SCALE = '0' const DEFAULT_SPIN_DEGREE = '30deg' -const DEFAULT_SLIDE_TRANSLATE = '100%' +export const DEFAULT_SLIDE_TRANSLATE = '100%' const DIRECTIONS_AUTOCOMPLETE = '(t|b|l|r|top|bottom|left|right)' @@ -64,40 +64,20 @@ const spinRules: Rule[] = [ ] -const _handleSlideValue = (val: string | undefined, dir: string | undefined): string | undefined => { - let value = h.cssvar.fraction.rem(val || DEFAULT_SLIDE_TRANSLATE) - - if (!value) - return - - dir = normalizeDirection(dir) - - if (!value.startsWith('var(--') && ['top', 'left'].includes(dir ?? '')) { - if (value.startsWith('-')) - value = value.slice(1) - else - value = `-${value}` - } - - return value -} - const slideRules: Rule[] = [ [ /^slide-in(?:-from)?-(t|b|l|r|top|bottom|left|right)(?:-(.+))?$/, ([, dir, val]) => { - const value = _handleSlideValue(val, dir) + const [value, direction] = handleSlide(val, dir) if (!value) return - switch (dir) { + switch (direction) { case 'top': - return { [`${CSS_VARIABLE_PREFIX}-enter-translate-y`]: `-${value}` } case 'bottom': return { [`${CSS_VARIABLE_PREFIX}-enter-translate-y`]: value } case 'left': - return { [`${CSS_VARIABLE_PREFIX}-enter-translate-x`]: `-${value}` } case 'right': return { [`${CSS_VARIABLE_PREFIX}-enter-translate-x`]: value } default: @@ -117,12 +97,12 @@ const slideRules: Rule[] = [ [ /^slide-out(?:-to)?-(t|b|l|r|top|bottom|left|right)(?:-(.+))?$/, ([, dir, val]) => { - const value = _handleSlideValue(val, dir) + const [value, direction] = handleSlide(val, dir) if (!value) return - switch (dir) { + switch (direction) { case 'top': case 'bottom': return { [`${CSS_VARIABLE_PREFIX}-exit-translate-y`]: value } diff --git a/src/shortcuts.ts b/src/shortcuts.ts index f575253..23d3235 100644 --- a/src/shortcuts.ts +++ b/src/shortcuts.ts @@ -1,4 +1,4 @@ -import { CSS_VARIABLE_PREFIX, ENTER_ANIMATION_NAME, EXIT_ANIMATION_NAME } from './constants' +import { CSS_VARIABLE_PREFIX, ENTER_ANIMATION_NAME, EXIT_ANIMATION_NAME } from '@/constants' import type { Theme } from '@unocss/preset-mini' import type { UserShortcuts } from 'unocss' diff --git a/src/theme.ts b/src/theme.ts index 3778da6..e1681fa 100644 --- a/src/theme.ts +++ b/src/theme.ts @@ -1,4 +1,4 @@ -import { CSS_VARIABLE_PREFIX, ENTER_ANIMATION_NAME, EXIT_ANIMATION_NAME } from './constants' +import { CSS_VARIABLE_PREFIX, ENTER_ANIMATION_NAME, EXIT_ANIMATION_NAME } from '@/constants' import type { Theme } from '@unocss/preset-mini' diff --git a/src/utils.ts b/src/utils.ts index eeb8289..f5fb411 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,8 @@ -export const normalizeDirection = (dir: string | undefined): string | undefined => { +import { h } from '@unocss/preset-mini/utils' +import { DEFAULT_SLIDE_TRANSLATE } from '@/rules' + + +const normalizeDirection = (dir: string | undefined): string | undefined => { const dirMap: Record = { t: 'top', b: 'bottom', @@ -8,3 +12,25 @@ export const normalizeDirection = (dir: string | undefined): string | undefined return dirMap[dir ?? ''] ?? dir } + + +export const handleSlide = ( + val: string | undefined, + dir: string | undefined +): [value?: string | undefined, direction?: string | undefined] => { + let value = h.cssvar.fraction.rem(val || DEFAULT_SLIDE_TRANSLATE) + + if (!value) + return [] + + dir = normalizeDirection(dir) + + if (!value.startsWith('var(--') && ['top', 'left'].includes(dir ?? '')) { + if (value.startsWith('-')) + value = value.slice(1) + else + value = `-${value}` + } + + return [value, dir] +} diff --git a/test/base.test.ts b/test/base.test.ts new file mode 100644 index 0000000..661ea91 --- /dev/null +++ b/test/base.test.ts @@ -0,0 +1,36 @@ +import { describe, it, expect } from 'vitest' +import { generator, uno } from '~/utils' + + +describe('base classname', () => { + it('"animate-in" should generate enter keyframe and css variables', async () => { + const { css } = await uno.generate('animate-in') + + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + @keyframes una-in{from{opacity:var(--una-enter-opacity,1);transform:translate3d(var(--una-enter-translate-x,0),var(--una-enter-translate-y,0),0) scale3d(var(--una-enter-scale,1),var(--una-enter-scale,1),var(--una-enter-scale,1)) rotate(var(--una-enter-rotate,0))}} + .animate-in{animation:una-in;animation-name:una-in;animation-duration:150ms;--una-enter-opacity:initial;--una-enter-scale:initial;--una-enter-rotate:initial;--una-enter-translate-x:initial;--una-enter-translate-y:initial;}" + `) + }) + + + it('"animate-out" should generate exit keyframe and css variables', async () => { + const { css } = await uno.generate('animate-out') + + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + @keyframes una-out{to{opacity:var(--una-exit-opacity,1);transform:translate3d(var(--una-exit-translate-x,0),var(--una-exit-translate-y,0),0) scale3d(var(--una-exit-scale,1),var(--una-exit-scale,1),var(--una-exit-scale,1)) rotate(var(--una-exit-rotate,0))}} + .animate-out{animation:una-out;animation-name:una-out;animation-duration:150ms;--una-exit-opacity:initial;--una-exit-scale:initial;--una-exit-rotate:initial;--una-exit-translate-x:initial;--una-exit-translate-y:initial;}" + `) + }) + + + it('"animation-duration" should be default to "theme.duration"', async () => { + const DURATION = '500ms' + + const uno = generator({ duration: { DEFAULT: DURATION } }) + const { css } = await uno.generate('animate-in') + + expect(css).toContain(`animation-duration:${DURATION};`) + }) +}) diff --git a/test/data/index.ts b/test/data/index.ts new file mode 100644 index 0000000..85385dd --- /dev/null +++ b/test/data/index.ts @@ -0,0 +1,9 @@ +export const INTEGERS_0_TO_100 = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100] +export const INTEGERS = [-200, -190, -180, -170, -160, -150, -140, -130, -120, -110, -100, -90, -80, -70, -60, -50, -40, -30, -20, -10, ...INTEGERS_0_TO_100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200] + +export const DECIMALS_0_TO_100 = [0.1, 10.1, 52.1, 66.66, 99.9] +export const DECIMALS = [-199.9, -180.37, -66.66, -52.1, -10.1, -0.1, ...DECIMALS_0_TO_100, 180.37, 199.9] + +export const FRACTIONS = ['-1/6', '-5/6', '-1/4', '-3/4', '-1/3', '-2/3', '1/6', '5/6', '1/4', '3/4', '1/3', '2/3'] + +export const CSS_VARIABLES = ['$foo', '$foo-bar', '$fooBar'] diff --git a/test/fade.test.ts b/test/fade.test.ts new file mode 100644 index 0000000..91834c1 --- /dev/null +++ b/test/fade.test.ts @@ -0,0 +1,142 @@ +import { describe, it, expect } from 'vitest' +import { CSS_VARIABLE_PREFIX } from '@/constants' +import { CSS_VARIABLES, DECIMALS_0_TO_100, INTEGERS_0_TO_100 } from '~/data' +import { uno } from '~/utils' + + +describe('fade animation', () => { + describe('fade-in', () => { + it(`should generate "${CSS_VARIABLE_PREFIX}-enter-opacity" css variable and default to "0"`, async () => { + const { css } = await uno.generate('fade-in') + + expect(css).toContain(`.fade-in{${CSS_VARIABLE_PREFIX}-enter-opacity:0;}`) + }) + + + describe('percentage', () => { + it(`should covert percentages from "0" to "100"`, async () => { + const classnames = INTEGERS_0_TO_100.map(i => `fade-in-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .fade-in-0{--una-enter-opacity:0;} + .fade-in-10{--una-enter-opacity:0.1;} + .fade-in-100{--una-enter-opacity:1;} + .fade-in-20{--una-enter-opacity:0.2;} + .fade-in-30{--una-enter-opacity:0.3;} + .fade-in-40{--una-enter-opacity:0.4;} + .fade-in-50{--una-enter-opacity:0.5;} + .fade-in-60{--una-enter-opacity:0.6;} + .fade-in-70{--una-enter-opacity:0.7;} + .fade-in-80{--una-enter-opacity:0.8;} + .fade-in-90{--una-enter-opacity:0.9;}" + `) + }) + + + it(`should also convert decimals`, async () => { + const classnames = DECIMALS_0_TO_100.map(i => `fade-in-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .fade-in-0\\\\.1{--una-enter-opacity:0.001;} + .fade-in-10\\\\.1{--una-enter-opacity:0.101;} + .fade-in-52\\\\.1{--una-enter-opacity:0.521;} + .fade-in-66\\\\.66{--una-enter-opacity:0.6666;} + .fade-in-99\\\\.9{--una-enter-opacity:0.999;}" + `) + }) + }) + + + describe('css variable', () => { + it(`should handle css variables`, async () => { + const classnames = CSS_VARIABLES.map(i => `fade-in-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .fade-in-\\\\$foo{--una-enter-opacity:var(--foo);} + .fade-in-\\\\$foo-bar{--una-enter-opacity:var(--foo-bar);} + .fade-in-\\\\$fooBar{--una-enter-opacity:var(--fooBar);}" + `) + }) + }) + }) + + + describe('fade-out', () => { + it(`should generate "${CSS_VARIABLE_PREFIX}-exit-opacity" css variable and default to "0"`, async () => { + const { css } = await uno.generate('fade-out') + + expect(css).toContain(`.fade-out{${CSS_VARIABLE_PREFIX}-exit-opacity:0;}`) + }) + + + describe('percentage', () => { + it(`should covert percentages from "0" to "100"`, async () => { + const classnames = INTEGERS_0_TO_100.map(i => `fade-out-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .fade-out-0{--una-exit-opacity:0;} + .fade-out-10{--una-exit-opacity:0.1;} + .fade-out-100{--una-exit-opacity:1;} + .fade-out-20{--una-exit-opacity:0.2;} + .fade-out-30{--una-exit-opacity:0.3;} + .fade-out-40{--una-exit-opacity:0.4;} + .fade-out-50{--una-exit-opacity:0.5;} + .fade-out-60{--una-exit-opacity:0.6;} + .fade-out-70{--una-exit-opacity:0.7;} + .fade-out-80{--una-exit-opacity:0.8;} + .fade-out-90{--una-exit-opacity:0.9;}" + `) + }) + + + it(`should also convert decimals`, async () => { + const classnames = DECIMALS_0_TO_100.map(i => `fade-out-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .fade-out-0\\\\.1{--una-exit-opacity:0.001;} + .fade-out-10\\\\.1{--una-exit-opacity:0.101;} + .fade-out-52\\\\.1{--una-exit-opacity:0.521;} + .fade-out-66\\\\.66{--una-exit-opacity:0.6666;} + .fade-out-99\\\\.9{--una-exit-opacity:0.999;}" + `) + }) + }) + + + describe('css variable', () => { + it(`should handle css variables`, async () => { + const classnames = CSS_VARIABLES.map(i => `fade-out-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .fade-out-\\\\$foo{--una-exit-opacity:var(--foo);} + .fade-out-\\\\$foo-bar{--una-exit-opacity:var(--foo-bar);} + .fade-out-\\\\$fooBar{--una-exit-opacity:var(--fooBar);}" + `) + }) + }) + }) +}) diff --git a/test/slide.test.ts b/test/slide.test.ts new file mode 100644 index 0000000..500fcfe --- /dev/null +++ b/test/slide.test.ts @@ -0,0 +1,616 @@ +import { describe, it, expect } from 'vitest' +import { CSS_VARIABLE_PREFIX } from '@/constants' +import { CSS_VARIABLES, DECIMALS, FRACTIONS, INTEGERS } from '~/data' +import { uno } from '~/utils' + + +describe('slide animation', () => { + describe('slide-in', () => { + describe('misc', () => { + it(`"should generate "${CSS_VARIABLE_PREFIX}-enter-translate-x" and "-y" css variable and default to "100%"`, async () => { + const classnames = [ + 'slide-in-t', + 'slide-in-b', + 'slide-in-l', + 'slide-in-r' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-in-b{--una-enter-translate-y:100%;} + .slide-in-l{--una-enter-translate-x:-100%;} + .slide-in-r{--una-enter-translate-x:100%;} + .slide-in-t{--una-enter-translate-y:-100%;}" + `) + }) + + + it(`should handle both with or without "-from"`, async () => { + const classnames = [ + 'slide-in-t', + 'slide-in-b', + 'slide-in-l', + 'slide-in-r', + 'slide-in-from-t', + 'slide-in-from-b', + 'slide-in-from-l', + 'slide-in-from-r' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-in-b, + .slide-in-from-b{--una-enter-translate-y:100%;} + .slide-in-from-l, + .slide-in-l{--una-enter-translate-x:-100%;} + .slide-in-from-r, + .slide-in-r{--una-enter-translate-x:100%;} + .slide-in-from-t, + .slide-in-t{--una-enter-translate-y:-100%;}" + `) + }) + + + it(`should alias "t|b|l|r" to "top|bottom|left|right"`, async () => { + const classnames = [ + 'slide-in-t', + 'slide-in-b', + 'slide-in-l', + 'slide-in-r', + 'slide-in-top', + 'slide-in-bottom', + 'slide-in-left', + 'slide-in-right' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-in-b, + .slide-in-bottom{--una-enter-translate-y:100%;} + .slide-in-l, + .slide-in-left{--una-enter-translate-x:-100%;} + .slide-in-r, + .slide-in-right{--una-enter-translate-x:100%;} + .slide-in-t, + .slide-in-top{--una-enter-translate-y:-100%;}" + `) + }) + }) + + + describe('direction', () => { + it(`should generate "top|bottom" as "translate-y"`, async () => { + const classnames = [ + 'slide-in-t', + 'slide-in-b' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-in-b{--una-enter-translate-y:100%;} + .slide-in-t{--una-enter-translate-y:-100%;}" + `) + }) + + + it(`should generate "left|right" as "translate-x"`, async () => { + const classnames = [ + 'slide-in-l', + 'slide-in-r' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-in-l{--una-enter-translate-x:-100%;} + .slide-in-r{--una-enter-translate-x:100%;}" + `) + }) + }) + + + describe('positivity and negativity', () => { + it(`should generate negative value for "top|left"`, async () => { + const classnames = [ + 'slide-in-t', + 'slide-in-l' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-in-l{--una-enter-translate-x:-100%;} + .slide-in-t{--una-enter-translate-y:-100%;}" + `) + }) + + + it(`should generate positive value for "bottom|right"`, async () => { + const classnames = [ + 'slide-in-b', + 'slide-in-r' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-in-b{--una-enter-translate-y:100%;} + .slide-in-r{--una-enter-translate-x:100%;}" + `) + }) + + + it(`should convert negative value to positive for "top|left"`, async () => { + const classnames = [ + 'slide-in-t--10', + 'slide-in-l--10' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-in-l--10{--una-enter-translate-x:2.5rem;} + .slide-in-t--10{--una-enter-translate-y:2.5rem;}" + `) + }) + }) + + + describe('rem', () => { + it(`should covert any numbers to "rem" (x / 4rem) including negative`, async () => { + const classnames = INTEGERS.map(i => `slide-in-t-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-in-t--10{--una-enter-translate-y:2.5rem;} + .slide-in-t--100{--una-enter-translate-y:25rem;} + .slide-in-t--110{--una-enter-translate-y:27.5rem;} + .slide-in-t--120{--una-enter-translate-y:30rem;} + .slide-in-t--130{--una-enter-translate-y:32.5rem;} + .slide-in-t--140{--una-enter-translate-y:35rem;} + .slide-in-t--150{--una-enter-translate-y:37.5rem;} + .slide-in-t--160{--una-enter-translate-y:40rem;} + .slide-in-t--170{--una-enter-translate-y:42.5rem;} + .slide-in-t--180{--una-enter-translate-y:45rem;} + .slide-in-t--190{--una-enter-translate-y:47.5rem;} + .slide-in-t--20{--una-enter-translate-y:5rem;} + .slide-in-t--200{--una-enter-translate-y:50rem;} + .slide-in-t--30{--una-enter-translate-y:7.5rem;} + .slide-in-t--40{--una-enter-translate-y:10rem;} + .slide-in-t--50{--una-enter-translate-y:12.5rem;} + .slide-in-t--60{--una-enter-translate-y:15rem;} + .slide-in-t--70{--una-enter-translate-y:17.5rem;} + .slide-in-t--80{--una-enter-translate-y:20rem;} + .slide-in-t--90{--una-enter-translate-y:22.5rem;} + .slide-in-t-0{--una-enter-translate-y:-0;} + .slide-in-t-10{--una-enter-translate-y:-2.5rem;} + .slide-in-t-100{--una-enter-translate-y:-25rem;} + .slide-in-t-110{--una-enter-translate-y:-27.5rem;} + .slide-in-t-120{--una-enter-translate-y:-30rem;} + .slide-in-t-130{--una-enter-translate-y:-32.5rem;} + .slide-in-t-140{--una-enter-translate-y:-35rem;} + .slide-in-t-150{--una-enter-translate-y:-37.5rem;} + .slide-in-t-160{--una-enter-translate-y:-40rem;} + .slide-in-t-170{--una-enter-translate-y:-42.5rem;} + .slide-in-t-180{--una-enter-translate-y:-45rem;} + .slide-in-t-190{--una-enter-translate-y:-47.5rem;} + .slide-in-t-20{--una-enter-translate-y:-5rem;} + .slide-in-t-200{--una-enter-translate-y:-50rem;} + .slide-in-t-30{--una-enter-translate-y:-7.5rem;} + .slide-in-t-40{--una-enter-translate-y:-10rem;} + .slide-in-t-50{--una-enter-translate-y:-12.5rem;} + .slide-in-t-60{--una-enter-translate-y:-15rem;} + .slide-in-t-70{--una-enter-translate-y:-17.5rem;} + .slide-in-t-80{--una-enter-translate-y:-20rem;} + .slide-in-t-90{--una-enter-translate-y:-22.5rem;}" + `) + }) + + + it(`should also convert decimals including negative`, async () => { + const classnames = DECIMALS.map(i => `slide-in-t-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-in-t--0\\\\.1{--una-enter-translate-y:0.025rem;} + .slide-in-t--10\\\\.1{--una-enter-translate-y:2.525rem;} + .slide-in-t--180\\\\.37{--una-enter-translate-y:45.0925rem;} + .slide-in-t--199\\\\.9{--una-enter-translate-y:49.975rem;} + .slide-in-t--52\\\\.1{--una-enter-translate-y:13.025rem;} + .slide-in-t--66\\\\.66{--una-enter-translate-y:16.665rem;} + .slide-in-t-0\\\\.1{--una-enter-translate-y:-0.025rem;} + .slide-in-t-10\\\\.1{--una-enter-translate-y:-2.525rem;} + .slide-in-t-180\\\\.37{--una-enter-translate-y:-45.0925rem;} + .slide-in-t-199\\\\.9{--una-enter-translate-y:-49.975rem;} + .slide-in-t-52\\\\.1{--una-enter-translate-y:-13.025rem;} + .slide-in-t-66\\\\.66{--una-enter-translate-y:-16.665rem;} + .slide-in-t-99\\\\.9{--una-enter-translate-y:-24.975rem;}" + `) + }) + }) + + + describe('fraction', () => { + it(`should covert any fractions including negative`, async () => { + const classnames = FRACTIONS.map(i => `slide-in-t-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-in-t--1\\\\/3{--una-enter-translate-y:33.3333333333%;} + .slide-in-t--1\\\\/4{--una-enter-translate-y:25%;} + .slide-in-t--1\\\\/6{--una-enter-translate-y:16.6666666667%;} + .slide-in-t--2\\\\/3{--una-enter-translate-y:66.6666666667%;} + .slide-in-t--3\\\\/4{--una-enter-translate-y:75%;} + .slide-in-t--5\\\\/6{--una-enter-translate-y:83.3333333333%;} + .slide-in-t-1\\\\/3{--una-enter-translate-y:-33.3333333333%;} + .slide-in-t-1\\\\/4{--una-enter-translate-y:-25%;} + .slide-in-t-1\\\\/6{--una-enter-translate-y:-16.6666666667%;} + .slide-in-t-2\\\\/3{--una-enter-translate-y:-66.6666666667%;} + .slide-in-t-3\\\\/4{--una-enter-translate-y:-75%;} + .slide-in-t-5\\\\/6{--una-enter-translate-y:-83.3333333333%;}" + `) + }) + + + it(`should convert "full" to "100%`, async () => { + const { css } = await uno.generate('slide-in-t-full') + + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-in-t-full{--una-enter-translate-y:-100%;}" + `) + }) + }) + + + describe('css variable', () => { + it(`should handle css variables`, async () => { + const classnames = CSS_VARIABLES.map(i => `slide-in-t-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-in-t-\\\\$foo{--una-enter-translate-y:var(--foo);} + .slide-in-t-\\\\$foo-bar{--una-enter-translate-y:var(--foo-bar);} + .slide-in-t-\\\\$fooBar{--una-enter-translate-y:var(--fooBar);}" + `) + }) + }) + }) + + + describe('slide-out', () => { + describe('misc', () => { + it(`"should generate "${CSS_VARIABLE_PREFIX}-exit-translate-x" and "-y" css variable and default to "100%"`, async () => { + const classnames = [ + 'slide-out-t', + 'slide-out-b', + 'slide-out-l', + 'slide-out-r' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-out-b{--una-exit-translate-y:100%;} + .slide-out-l{--una-exit-translate-x:-100%;} + .slide-out-r{--una-exit-translate-x:100%;} + .slide-out-t{--una-exit-translate-y:-100%;}" + `) + }) + + + it(`should handle both with or without "-to"`, async () => { + const classnames = [ + 'slide-out-t', + 'slide-out-b', + 'slide-out-l', + 'slide-out-r', + 'slide-out-to-t', + 'slide-out-to-b', + 'slide-out-to-l', + 'slide-out-to-r' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-out-b, + .slide-out-to-b{--una-exit-translate-y:100%;} + .slide-out-l, + .slide-out-to-l{--una-exit-translate-x:-100%;} + .slide-out-r, + .slide-out-to-r{--una-exit-translate-x:100%;} + .slide-out-t, + .slide-out-to-t{--una-exit-translate-y:-100%;}" + `) + }) + + + it(`should alias "t|b|l|r" to "top|bottom|left|right"`, async () => { + const classnames = [ + 'slide-out-t', + 'slide-out-b', + 'slide-out-l', + 'slide-out-r', + 'slide-out-top', + 'slide-out-bottom', + 'slide-out-left', + 'slide-out-right' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-out-b, + .slide-out-bottom{--una-exit-translate-y:100%;} + .slide-out-l, + .slide-out-left{--una-exit-translate-x:-100%;} + .slide-out-r, + .slide-out-right{--una-exit-translate-x:100%;} + .slide-out-t, + .slide-out-top{--una-exit-translate-y:-100%;}" + `) + }) + }) + + + describe('direction', () => { + it(`should generate "top|bottom" as "translate-y"`, async () => { + const classnames = [ + 'slide-out-t', + 'slide-out-b' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-out-b{--una-exit-translate-y:100%;} + .slide-out-t{--una-exit-translate-y:-100%;}" + `) + }) + + + it(`should generate "left|right" as "translate-x"`, async () => { + const classnames = [ + 'slide-out-l', + 'slide-out-r' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-out-l{--una-exit-translate-x:-100%;} + .slide-out-r{--una-exit-translate-x:100%;}" + `) + }) + }) + + + describe('positivity and negativity', () => { + it(`should generate negative value for "top|left"`, async () => { + const classnames = [ + 'slide-out-t', + 'slide-out-l' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-out-l{--una-exit-translate-x:-100%;} + .slide-out-t{--una-exit-translate-y:-100%;}" + `) + }) + + + it(`should generate positive value for "bottom|right"`, async () => { + const classnames = [ + 'slide-out-b', + 'slide-out-r' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-out-b{--una-exit-translate-y:100%;} + .slide-out-r{--una-exit-translate-x:100%;}" + `) + }) + + + it(`should convert negative value to positive for "top|left"`, async () => { + const classnames = [ + 'slide-out-t--10', + 'slide-out-l--10' + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-out-l--10{--una-exit-translate-x:2.5rem;} + .slide-out-t--10{--una-exit-translate-y:2.5rem;}" + `) + }) + }) + + + describe('rem', () => { + it(`should covert any numbers to "rem" (x / 4rem) including negative`, async () => { + const classnames = INTEGERS.map(i => `slide-out-t-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-out-t--10{--una-exit-translate-y:2.5rem;} + .slide-out-t--100{--una-exit-translate-y:25rem;} + .slide-out-t--110{--una-exit-translate-y:27.5rem;} + .slide-out-t--120{--una-exit-translate-y:30rem;} + .slide-out-t--130{--una-exit-translate-y:32.5rem;} + .slide-out-t--140{--una-exit-translate-y:35rem;} + .slide-out-t--150{--una-exit-translate-y:37.5rem;} + .slide-out-t--160{--una-exit-translate-y:40rem;} + .slide-out-t--170{--una-exit-translate-y:42.5rem;} + .slide-out-t--180{--una-exit-translate-y:45rem;} + .slide-out-t--190{--una-exit-translate-y:47.5rem;} + .slide-out-t--20{--una-exit-translate-y:5rem;} + .slide-out-t--200{--una-exit-translate-y:50rem;} + .slide-out-t--30{--una-exit-translate-y:7.5rem;} + .slide-out-t--40{--una-exit-translate-y:10rem;} + .slide-out-t--50{--una-exit-translate-y:12.5rem;} + .slide-out-t--60{--una-exit-translate-y:15rem;} + .slide-out-t--70{--una-exit-translate-y:17.5rem;} + .slide-out-t--80{--una-exit-translate-y:20rem;} + .slide-out-t--90{--una-exit-translate-y:22.5rem;} + .slide-out-t-0{--una-exit-translate-y:-0;} + .slide-out-t-10{--una-exit-translate-y:-2.5rem;} + .slide-out-t-100{--una-exit-translate-y:-25rem;} + .slide-out-t-110{--una-exit-translate-y:-27.5rem;} + .slide-out-t-120{--una-exit-translate-y:-30rem;} + .slide-out-t-130{--una-exit-translate-y:-32.5rem;} + .slide-out-t-140{--una-exit-translate-y:-35rem;} + .slide-out-t-150{--una-exit-translate-y:-37.5rem;} + .slide-out-t-160{--una-exit-translate-y:-40rem;} + .slide-out-t-170{--una-exit-translate-y:-42.5rem;} + .slide-out-t-180{--una-exit-translate-y:-45rem;} + .slide-out-t-190{--una-exit-translate-y:-47.5rem;} + .slide-out-t-20{--una-exit-translate-y:-5rem;} + .slide-out-t-200{--una-exit-translate-y:-50rem;} + .slide-out-t-30{--una-exit-translate-y:-7.5rem;} + .slide-out-t-40{--una-exit-translate-y:-10rem;} + .slide-out-t-50{--una-exit-translate-y:-12.5rem;} + .slide-out-t-60{--una-exit-translate-y:-15rem;} + .slide-out-t-70{--una-exit-translate-y:-17.5rem;} + .slide-out-t-80{--una-exit-translate-y:-20rem;} + .slide-out-t-90{--una-exit-translate-y:-22.5rem;}" + `) + }) + + + it(`should also convert decimals including negative`, async () => { + const classnames = DECIMALS.map(i => `slide-out-t-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-out-t--0\\\\.1{--una-exit-translate-y:0.025rem;} + .slide-out-t--10\\\\.1{--una-exit-translate-y:2.525rem;} + .slide-out-t--180\\\\.37{--una-exit-translate-y:45.0925rem;} + .slide-out-t--199\\\\.9{--una-exit-translate-y:49.975rem;} + .slide-out-t--52\\\\.1{--una-exit-translate-y:13.025rem;} + .slide-out-t--66\\\\.66{--una-exit-translate-y:16.665rem;} + .slide-out-t-0\\\\.1{--una-exit-translate-y:-0.025rem;} + .slide-out-t-10\\\\.1{--una-exit-translate-y:-2.525rem;} + .slide-out-t-180\\\\.37{--una-exit-translate-y:-45.0925rem;} + .slide-out-t-199\\\\.9{--una-exit-translate-y:-49.975rem;} + .slide-out-t-52\\\\.1{--una-exit-translate-y:-13.025rem;} + .slide-out-t-66\\\\.66{--una-exit-translate-y:-16.665rem;} + .slide-out-t-99\\\\.9{--una-exit-translate-y:-24.975rem;}" + `) + }) + }) + + + describe('fraction', () => { + it(`should covert any fractions including negative`, async () => { + const classnames = FRACTIONS.map(i => `slide-out-t-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-out-t--1\\\\/3{--una-exit-translate-y:33.3333333333%;} + .slide-out-t--1\\\\/4{--una-exit-translate-y:25%;} + .slide-out-t--1\\\\/6{--una-exit-translate-y:16.6666666667%;} + .slide-out-t--2\\\\/3{--una-exit-translate-y:66.6666666667%;} + .slide-out-t--3\\\\/4{--una-exit-translate-y:75%;} + .slide-out-t--5\\\\/6{--una-exit-translate-y:83.3333333333%;} + .slide-out-t-1\\\\/3{--una-exit-translate-y:-33.3333333333%;} + .slide-out-t-1\\\\/4{--una-exit-translate-y:-25%;} + .slide-out-t-1\\\\/6{--una-exit-translate-y:-16.6666666667%;} + .slide-out-t-2\\\\/3{--una-exit-translate-y:-66.6666666667%;} + .slide-out-t-3\\\\/4{--una-exit-translate-y:-75%;} + .slide-out-t-5\\\\/6{--una-exit-translate-y:-83.3333333333%;}" + `) + }) + + + it(`should convert "full" to "100%`, async () => { + const { css } = await uno.generate('slide-out-t-full') + + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-out-t-full{--una-exit-translate-y:-100%;}" + `) + }) + }) + + + describe('css variable', () => { + it(`should handle css variables`, async () => { + const classnames = CSS_VARIABLES.map(i => `slide-out-t-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .slide-out-t-\\\\$foo{--una-exit-translate-y:var(--foo);} + .slide-out-t-\\\\$foo-bar{--una-exit-translate-y:var(--foo-bar);} + .slide-out-t-\\\\$fooBar{--una-exit-translate-y:var(--fooBar);}" + `) + }) + }) + }) +}) diff --git a/test/spin.test.ts b/test/spin.test.ts new file mode 100644 index 0000000..323979b --- /dev/null +++ b/test/spin.test.ts @@ -0,0 +1,621 @@ +import { describe, it, expect } from 'vitest' +import { CSS_VARIABLE_PREFIX } from '@/constants' +import { CSS_VARIABLES, DECIMALS, INTEGERS } from '~/data' +import { uno } from '~/utils' + + +describe('spin animation', () => { + describe('spin-in', () => { + it(`should generate "${CSS_VARIABLE_PREFIX}-enter-rotate" css variable and default to "30deg"`, async () => { + const { css } = await uno.generate('spin-in') + + expect(css).toContain(`.spin-in{${CSS_VARIABLE_PREFIX}-enter-rotate:30deg;}`) + }) + + + describe('angle', () => { + it(`should handle any numbers including negative and unit default to "deg"`, async () => { + const classnames = INTEGERS.map(i => `spin-in-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .spin-in--10{--una-enter-rotate:-10deg;} + .spin-in--100{--una-enter-rotate:-100deg;} + .spin-in--110{--una-enter-rotate:-110deg;} + .spin-in--120{--una-enter-rotate:-120deg;} + .spin-in--130{--una-enter-rotate:-130deg;} + .spin-in--140{--una-enter-rotate:-140deg;} + .spin-in--150{--una-enter-rotate:-150deg;} + .spin-in--160{--una-enter-rotate:-160deg;} + .spin-in--170{--una-enter-rotate:-170deg;} + .spin-in--180{--una-enter-rotate:-180deg;} + .spin-in--190{--una-enter-rotate:-190deg;} + .spin-in--20{--una-enter-rotate:-20deg;} + .spin-in--200{--una-enter-rotate:-200deg;} + .spin-in--30{--una-enter-rotate:-30deg;} + .spin-in--40{--una-enter-rotate:-40deg;} + .spin-in--50{--una-enter-rotate:-50deg;} + .spin-in--60{--una-enter-rotate:-60deg;} + .spin-in--70{--una-enter-rotate:-70deg;} + .spin-in--80{--una-enter-rotate:-80deg;} + .spin-in--90{--una-enter-rotate:-90deg;} + .spin-in-0{--una-enter-rotate:0;} + .spin-in-10{--una-enter-rotate:10deg;} + .spin-in-100{--una-enter-rotate:100deg;} + .spin-in-110{--una-enter-rotate:110deg;} + .spin-in-120{--una-enter-rotate:120deg;} + .spin-in-130{--una-enter-rotate:130deg;} + .spin-in-140{--una-enter-rotate:140deg;} + .spin-in-150{--una-enter-rotate:150deg;} + .spin-in-160{--una-enter-rotate:160deg;} + .spin-in-170{--una-enter-rotate:170deg;} + .spin-in-180{--una-enter-rotate:180deg;} + .spin-in-190{--una-enter-rotate:190deg;} + .spin-in-20{--una-enter-rotate:20deg;} + .spin-in-200{--una-enter-rotate:200deg;} + .spin-in-30{--una-enter-rotate:30deg;} + .spin-in-40{--una-enter-rotate:40deg;} + .spin-in-50{--una-enter-rotate:50deg;} + .spin-in-60{--una-enter-rotate:60deg;} + .spin-in-70{--una-enter-rotate:70deg;} + .spin-in-80{--una-enter-rotate:80deg;} + .spin-in-90{--una-enter-rotate:90deg;}" + `) + }) + + + it(`should also handle decimals including negative`, async () => { + const classnames = DECIMALS.map(i => `spin-in-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .spin-in--0\\\\.1{--una-enter-rotate:-0.1deg;} + .spin-in--10\\\\.1{--una-enter-rotate:-10.1deg;} + .spin-in--180\\\\.37{--una-enter-rotate:-180.37deg;} + .spin-in--199\\\\.9{--una-enter-rotate:-199.9deg;} + .spin-in--52\\\\.1{--una-enter-rotate:-52.1deg;} + .spin-in--66\\\\.66{--una-enter-rotate:-66.66deg;} + .spin-in-0\\\\.1{--una-enter-rotate:0.1deg;} + .spin-in-10\\\\.1{--una-enter-rotate:10.1deg;} + .spin-in-180\\\\.37{--una-enter-rotate:180.37deg;} + .spin-in-199\\\\.9{--una-enter-rotate:199.9deg;} + .spin-in-52\\\\.1{--una-enter-rotate:52.1deg;} + .spin-in-66\\\\.66{--una-enter-rotate:66.66deg;} + .spin-in-99\\\\.9{--una-enter-rotate:99.9deg;}" + `) + }) + + + it(`should use units ("deg", "rad", "grad", "turn") as is`, async () => { + const DATASET = INTEGERS.filter(Boolean) + + const classnames = [ + ...DATASET.map(i => `spin-in-${i}deg`), + ...DATASET.map(i => `spin-in-${i}rad`), + ...DATASET.map(i => `spin-in-${i}grad`), + ...DATASET.map(i => `spin-in-${i}turn`) + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .spin-in--100deg{--una-enter-rotate:-100deg;} + .spin-in--100grad{--una-enter-rotate:-100grad;} + .spin-in--100rad{--una-enter-rotate:-100rad;} + .spin-in--100turn{--una-enter-rotate:-100turn;} + .spin-in--10deg{--una-enter-rotate:-10deg;} + .spin-in--10grad{--una-enter-rotate:-10grad;} + .spin-in--10rad{--una-enter-rotate:-10rad;} + .spin-in--10turn{--una-enter-rotate:-10turn;} + .spin-in--110deg{--una-enter-rotate:-110deg;} + .spin-in--110grad{--una-enter-rotate:-110grad;} + .spin-in--110rad{--una-enter-rotate:-110rad;} + .spin-in--110turn{--una-enter-rotate:-110turn;} + .spin-in--120deg{--una-enter-rotate:-120deg;} + .spin-in--120grad{--una-enter-rotate:-120grad;} + .spin-in--120rad{--una-enter-rotate:-120rad;} + .spin-in--120turn{--una-enter-rotate:-120turn;} + .spin-in--130deg{--una-enter-rotate:-130deg;} + .spin-in--130grad{--una-enter-rotate:-130grad;} + .spin-in--130rad{--una-enter-rotate:-130rad;} + .spin-in--130turn{--una-enter-rotate:-130turn;} + .spin-in--140deg{--una-enter-rotate:-140deg;} + .spin-in--140grad{--una-enter-rotate:-140grad;} + .spin-in--140rad{--una-enter-rotate:-140rad;} + .spin-in--140turn{--una-enter-rotate:-140turn;} + .spin-in--150deg{--una-enter-rotate:-150deg;} + .spin-in--150grad{--una-enter-rotate:-150grad;} + .spin-in--150rad{--una-enter-rotate:-150rad;} + .spin-in--150turn{--una-enter-rotate:-150turn;} + .spin-in--160deg{--una-enter-rotate:-160deg;} + .spin-in--160grad{--una-enter-rotate:-160grad;} + .spin-in--160rad{--una-enter-rotate:-160rad;} + .spin-in--160turn{--una-enter-rotate:-160turn;} + .spin-in--170deg{--una-enter-rotate:-170deg;} + .spin-in--170grad{--una-enter-rotate:-170grad;} + .spin-in--170rad{--una-enter-rotate:-170rad;} + .spin-in--170turn{--una-enter-rotate:-170turn;} + .spin-in--180deg{--una-enter-rotate:-180deg;} + .spin-in--180grad{--una-enter-rotate:-180grad;} + .spin-in--180rad{--una-enter-rotate:-180rad;} + .spin-in--180turn{--una-enter-rotate:-180turn;} + .spin-in--190deg{--una-enter-rotate:-190deg;} + .spin-in--190grad{--una-enter-rotate:-190grad;} + .spin-in--190rad{--una-enter-rotate:-190rad;} + .spin-in--190turn{--una-enter-rotate:-190turn;} + .spin-in--200deg{--una-enter-rotate:-200deg;} + .spin-in--200grad{--una-enter-rotate:-200grad;} + .spin-in--200rad{--una-enter-rotate:-200rad;} + .spin-in--200turn{--una-enter-rotate:-200turn;} + .spin-in--20deg{--una-enter-rotate:-20deg;} + .spin-in--20grad{--una-enter-rotate:-20grad;} + .spin-in--20rad{--una-enter-rotate:-20rad;} + .spin-in--20turn{--una-enter-rotate:-20turn;} + .spin-in--30deg{--una-enter-rotate:-30deg;} + .spin-in--30grad{--una-enter-rotate:-30grad;} + .spin-in--30rad{--una-enter-rotate:-30rad;} + .spin-in--30turn{--una-enter-rotate:-30turn;} + .spin-in--40deg{--una-enter-rotate:-40deg;} + .spin-in--40grad{--una-enter-rotate:-40grad;} + .spin-in--40rad{--una-enter-rotate:-40rad;} + .spin-in--40turn{--una-enter-rotate:-40turn;} + .spin-in--50deg{--una-enter-rotate:-50deg;} + .spin-in--50grad{--una-enter-rotate:-50grad;} + .spin-in--50rad{--una-enter-rotate:-50rad;} + .spin-in--50turn{--una-enter-rotate:-50turn;} + .spin-in--60deg{--una-enter-rotate:-60deg;} + .spin-in--60grad{--una-enter-rotate:-60grad;} + .spin-in--60rad{--una-enter-rotate:-60rad;} + .spin-in--60turn{--una-enter-rotate:-60turn;} + .spin-in--70deg{--una-enter-rotate:-70deg;} + .spin-in--70grad{--una-enter-rotate:-70grad;} + .spin-in--70rad{--una-enter-rotate:-70rad;} + .spin-in--70turn{--una-enter-rotate:-70turn;} + .spin-in--80deg{--una-enter-rotate:-80deg;} + .spin-in--80grad{--una-enter-rotate:-80grad;} + .spin-in--80rad{--una-enter-rotate:-80rad;} + .spin-in--80turn{--una-enter-rotate:-80turn;} + .spin-in--90deg{--una-enter-rotate:-90deg;} + .spin-in--90grad{--una-enter-rotate:-90grad;} + .spin-in--90rad{--una-enter-rotate:-90rad;} + .spin-in--90turn{--una-enter-rotate:-90turn;} + .spin-in-100deg{--una-enter-rotate:100deg;} + .spin-in-100grad{--una-enter-rotate:100grad;} + .spin-in-100rad{--una-enter-rotate:100rad;} + .spin-in-100turn{--una-enter-rotate:100turn;} + .spin-in-10deg{--una-enter-rotate:10deg;} + .spin-in-10grad{--una-enter-rotate:10grad;} + .spin-in-10rad{--una-enter-rotate:10rad;} + .spin-in-10turn{--una-enter-rotate:10turn;} + .spin-in-110deg{--una-enter-rotate:110deg;} + .spin-in-110grad{--una-enter-rotate:110grad;} + .spin-in-110rad{--una-enter-rotate:110rad;} + .spin-in-110turn{--una-enter-rotate:110turn;} + .spin-in-120deg{--una-enter-rotate:120deg;} + .spin-in-120grad{--una-enter-rotate:120grad;} + .spin-in-120rad{--una-enter-rotate:120rad;} + .spin-in-120turn{--una-enter-rotate:120turn;} + .spin-in-130deg{--una-enter-rotate:130deg;} + .spin-in-130grad{--una-enter-rotate:130grad;} + .spin-in-130rad{--una-enter-rotate:130rad;} + .spin-in-130turn{--una-enter-rotate:130turn;} + .spin-in-140deg{--una-enter-rotate:140deg;} + .spin-in-140grad{--una-enter-rotate:140grad;} + .spin-in-140rad{--una-enter-rotate:140rad;} + .spin-in-140turn{--una-enter-rotate:140turn;} + .spin-in-150deg{--una-enter-rotate:150deg;} + .spin-in-150grad{--una-enter-rotate:150grad;} + .spin-in-150rad{--una-enter-rotate:150rad;} + .spin-in-150turn{--una-enter-rotate:150turn;} + .spin-in-160deg{--una-enter-rotate:160deg;} + .spin-in-160grad{--una-enter-rotate:160grad;} + .spin-in-160rad{--una-enter-rotate:160rad;} + .spin-in-160turn{--una-enter-rotate:160turn;} + .spin-in-170deg{--una-enter-rotate:170deg;} + .spin-in-170grad{--una-enter-rotate:170grad;} + .spin-in-170rad{--una-enter-rotate:170rad;} + .spin-in-170turn{--una-enter-rotate:170turn;} + .spin-in-180deg{--una-enter-rotate:180deg;} + .spin-in-180grad{--una-enter-rotate:180grad;} + .spin-in-180rad{--una-enter-rotate:180rad;} + .spin-in-180turn{--una-enter-rotate:180turn;} + .spin-in-190deg{--una-enter-rotate:190deg;} + .spin-in-190grad{--una-enter-rotate:190grad;} + .spin-in-190rad{--una-enter-rotate:190rad;} + .spin-in-190turn{--una-enter-rotate:190turn;} + .spin-in-200deg{--una-enter-rotate:200deg;} + .spin-in-200grad{--una-enter-rotate:200grad;} + .spin-in-200rad{--una-enter-rotate:200rad;} + .spin-in-200turn{--una-enter-rotate:200turn;} + .spin-in-20deg{--una-enter-rotate:20deg;} + .spin-in-20grad{--una-enter-rotate:20grad;} + .spin-in-20rad{--una-enter-rotate:20rad;} + .spin-in-20turn{--una-enter-rotate:20turn;} + .spin-in-30deg{--una-enter-rotate:30deg;} + .spin-in-30grad{--una-enter-rotate:30grad;} + .spin-in-30rad{--una-enter-rotate:30rad;} + .spin-in-30turn{--una-enter-rotate:30turn;} + .spin-in-40deg{--una-enter-rotate:40deg;} + .spin-in-40grad{--una-enter-rotate:40grad;} + .spin-in-40rad{--una-enter-rotate:40rad;} + .spin-in-40turn{--una-enter-rotate:40turn;} + .spin-in-50deg{--una-enter-rotate:50deg;} + .spin-in-50grad{--una-enter-rotate:50grad;} + .spin-in-50rad{--una-enter-rotate:50rad;} + .spin-in-50turn{--una-enter-rotate:50turn;} + .spin-in-60deg{--una-enter-rotate:60deg;} + .spin-in-60grad{--una-enter-rotate:60grad;} + .spin-in-60rad{--una-enter-rotate:60rad;} + .spin-in-60turn{--una-enter-rotate:60turn;} + .spin-in-70deg{--una-enter-rotate:70deg;} + .spin-in-70grad{--una-enter-rotate:70grad;} + .spin-in-70rad{--una-enter-rotate:70rad;} + .spin-in-70turn{--una-enter-rotate:70turn;} + .spin-in-80deg{--una-enter-rotate:80deg;} + .spin-in-80grad{--una-enter-rotate:80grad;} + .spin-in-80rad{--una-enter-rotate:80rad;} + .spin-in-80turn{--una-enter-rotate:80turn;} + .spin-in-90deg{--una-enter-rotate:90deg;} + .spin-in-90grad{--una-enter-rotate:90grad;} + .spin-in-90rad{--una-enter-rotate:90rad;} + .spin-in-90turn{--una-enter-rotate:90turn;}" + `) + }) + + + it(`should not use any unit for "0"`, async () => { + const classnames = [ + 'spin-in-0', + 'spin-in-0deg', + 'spin-in-0rad', + 'spin-in-0grad', + 'spin-in-0turn' + ] + + const { matched, css } = await uno.generate(classnames) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .spin-in-0, + .spin-in-0deg, + .spin-in-0grad, + .spin-in-0rad, + .spin-in-0turn{--una-enter-rotate:0;}" + `) + }) + }) + + + describe('css variable', () => { + it(`should handle css variables`, async () => { + const classnames = CSS_VARIABLES.map(i => `spin-in-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .spin-in-\\\\$foo{--una-enter-rotate:var(--foo);} + .spin-in-\\\\$foo-bar{--una-enter-rotate:var(--foo-bar);} + .spin-in-\\\\$fooBar{--una-enter-rotate:var(--fooBar);}" + `) + }) + }) + }) + + + describe('spin-out', () => { + it(`should generate "${CSS_VARIABLE_PREFIX}-exit-rotate" css variable and default to "30deg"`, async () => { + const { css } = await uno.generate('spin-out') + + expect(css).toContain(`.spin-out{${CSS_VARIABLE_PREFIX}-exit-rotate:30deg;}`) + }) + + + describe('angle', () => { + it(`should handle any numbers including negative and unit default to "deg"`, async () => { + const classnames = INTEGERS.map(i => `spin-out-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .spin-out--10{--una-exit-rotate:-10deg;} + .spin-out--100{--una-exit-rotate:-100deg;} + .spin-out--110{--una-exit-rotate:-110deg;} + .spin-out--120{--una-exit-rotate:-120deg;} + .spin-out--130{--una-exit-rotate:-130deg;} + .spin-out--140{--una-exit-rotate:-140deg;} + .spin-out--150{--una-exit-rotate:-150deg;} + .spin-out--160{--una-exit-rotate:-160deg;} + .spin-out--170{--una-exit-rotate:-170deg;} + .spin-out--180{--una-exit-rotate:-180deg;} + .spin-out--190{--una-exit-rotate:-190deg;} + .spin-out--20{--una-exit-rotate:-20deg;} + .spin-out--200{--una-exit-rotate:-200deg;} + .spin-out--30{--una-exit-rotate:-30deg;} + .spin-out--40{--una-exit-rotate:-40deg;} + .spin-out--50{--una-exit-rotate:-50deg;} + .spin-out--60{--una-exit-rotate:-60deg;} + .spin-out--70{--una-exit-rotate:-70deg;} + .spin-out--80{--una-exit-rotate:-80deg;} + .spin-out--90{--una-exit-rotate:-90deg;} + .spin-out-0{--una-exit-rotate:0;} + .spin-out-10{--una-exit-rotate:10deg;} + .spin-out-100{--una-exit-rotate:100deg;} + .spin-out-110{--una-exit-rotate:110deg;} + .spin-out-120{--una-exit-rotate:120deg;} + .spin-out-130{--una-exit-rotate:130deg;} + .spin-out-140{--una-exit-rotate:140deg;} + .spin-out-150{--una-exit-rotate:150deg;} + .spin-out-160{--una-exit-rotate:160deg;} + .spin-out-170{--una-exit-rotate:170deg;} + .spin-out-180{--una-exit-rotate:180deg;} + .spin-out-190{--una-exit-rotate:190deg;} + .spin-out-20{--una-exit-rotate:20deg;} + .spin-out-200{--una-exit-rotate:200deg;} + .spin-out-30{--una-exit-rotate:30deg;} + .spin-out-40{--una-exit-rotate:40deg;} + .spin-out-50{--una-exit-rotate:50deg;} + .spin-out-60{--una-exit-rotate:60deg;} + .spin-out-70{--una-exit-rotate:70deg;} + .spin-out-80{--una-exit-rotate:80deg;} + .spin-out-90{--una-exit-rotate:90deg;}" + `) + }) + + + it(`should also handle decimals including negative`, async () => { + const classnames = DECIMALS.map(i => `spin-out-${i}`) + + const { css } = await uno.generate(classnames.join(' ')) + + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .spin-out--0\\\\.1{--una-exit-rotate:-0.1deg;} + .spin-out--10\\\\.1{--una-exit-rotate:-10.1deg;} + .spin-out--180\\\\.37{--una-exit-rotate:-180.37deg;} + .spin-out--199\\\\.9{--una-exit-rotate:-199.9deg;} + .spin-out--52\\\\.1{--una-exit-rotate:-52.1deg;} + .spin-out--66\\\\.66{--una-exit-rotate:-66.66deg;} + .spin-out-0\\\\.1{--una-exit-rotate:0.1deg;} + .spin-out-10\\\\.1{--una-exit-rotate:10.1deg;} + .spin-out-180\\\\.37{--una-exit-rotate:180.37deg;} + .spin-out-199\\\\.9{--una-exit-rotate:199.9deg;} + .spin-out-52\\\\.1{--una-exit-rotate:52.1deg;} + .spin-out-66\\\\.66{--una-exit-rotate:66.66deg;} + .spin-out-99\\\\.9{--una-exit-rotate:99.9deg;}" + `) + }) + + + it(`should use units ("deg", "rad", "grad", "turn") as is`, async () => { + const DATASET = INTEGERS.filter(Boolean) + + const classnames = [ + ...DATASET.map(i => `spin-out-${i}deg`), + ...DATASET.map(i => `spin-out-${i}rad`), + ...DATASET.map(i => `spin-out-${i}grad`), + ...DATASET.map(i => `spin-out-${i}turn`) + ] + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .spin-out--100deg{--una-exit-rotate:-100deg;} + .spin-out--100grad{--una-exit-rotate:-100grad;} + .spin-out--100rad{--una-exit-rotate:-100rad;} + .spin-out--100turn{--una-exit-rotate:-100turn;} + .spin-out--10deg{--una-exit-rotate:-10deg;} + .spin-out--10grad{--una-exit-rotate:-10grad;} + .spin-out--10rad{--una-exit-rotate:-10rad;} + .spin-out--10turn{--una-exit-rotate:-10turn;} + .spin-out--110deg{--una-exit-rotate:-110deg;} + .spin-out--110grad{--una-exit-rotate:-110grad;} + .spin-out--110rad{--una-exit-rotate:-110rad;} + .spin-out--110turn{--una-exit-rotate:-110turn;} + .spin-out--120deg{--una-exit-rotate:-120deg;} + .spin-out--120grad{--una-exit-rotate:-120grad;} + .spin-out--120rad{--una-exit-rotate:-120rad;} + .spin-out--120turn{--una-exit-rotate:-120turn;} + .spin-out--130deg{--una-exit-rotate:-130deg;} + .spin-out--130grad{--una-exit-rotate:-130grad;} + .spin-out--130rad{--una-exit-rotate:-130rad;} + .spin-out--130turn{--una-exit-rotate:-130turn;} + .spin-out--140deg{--una-exit-rotate:-140deg;} + .spin-out--140grad{--una-exit-rotate:-140grad;} + .spin-out--140rad{--una-exit-rotate:-140rad;} + .spin-out--140turn{--una-exit-rotate:-140turn;} + .spin-out--150deg{--una-exit-rotate:-150deg;} + .spin-out--150grad{--una-exit-rotate:-150grad;} + .spin-out--150rad{--una-exit-rotate:-150rad;} + .spin-out--150turn{--una-exit-rotate:-150turn;} + .spin-out--160deg{--una-exit-rotate:-160deg;} + .spin-out--160grad{--una-exit-rotate:-160grad;} + .spin-out--160rad{--una-exit-rotate:-160rad;} + .spin-out--160turn{--una-exit-rotate:-160turn;} + .spin-out--170deg{--una-exit-rotate:-170deg;} + .spin-out--170grad{--una-exit-rotate:-170grad;} + .spin-out--170rad{--una-exit-rotate:-170rad;} + .spin-out--170turn{--una-exit-rotate:-170turn;} + .spin-out--180deg{--una-exit-rotate:-180deg;} + .spin-out--180grad{--una-exit-rotate:-180grad;} + .spin-out--180rad{--una-exit-rotate:-180rad;} + .spin-out--180turn{--una-exit-rotate:-180turn;} + .spin-out--190deg{--una-exit-rotate:-190deg;} + .spin-out--190grad{--una-exit-rotate:-190grad;} + .spin-out--190rad{--una-exit-rotate:-190rad;} + .spin-out--190turn{--una-exit-rotate:-190turn;} + .spin-out--200deg{--una-exit-rotate:-200deg;} + .spin-out--200grad{--una-exit-rotate:-200grad;} + .spin-out--200rad{--una-exit-rotate:-200rad;} + .spin-out--200turn{--una-exit-rotate:-200turn;} + .spin-out--20deg{--una-exit-rotate:-20deg;} + .spin-out--20grad{--una-exit-rotate:-20grad;} + .spin-out--20rad{--una-exit-rotate:-20rad;} + .spin-out--20turn{--una-exit-rotate:-20turn;} + .spin-out--30deg{--una-exit-rotate:-30deg;} + .spin-out--30grad{--una-exit-rotate:-30grad;} + .spin-out--30rad{--una-exit-rotate:-30rad;} + .spin-out--30turn{--una-exit-rotate:-30turn;} + .spin-out--40deg{--una-exit-rotate:-40deg;} + .spin-out--40grad{--una-exit-rotate:-40grad;} + .spin-out--40rad{--una-exit-rotate:-40rad;} + .spin-out--40turn{--una-exit-rotate:-40turn;} + .spin-out--50deg{--una-exit-rotate:-50deg;} + .spin-out--50grad{--una-exit-rotate:-50grad;} + .spin-out--50rad{--una-exit-rotate:-50rad;} + .spin-out--50turn{--una-exit-rotate:-50turn;} + .spin-out--60deg{--una-exit-rotate:-60deg;} + .spin-out--60grad{--una-exit-rotate:-60grad;} + .spin-out--60rad{--una-exit-rotate:-60rad;} + .spin-out--60turn{--una-exit-rotate:-60turn;} + .spin-out--70deg{--una-exit-rotate:-70deg;} + .spin-out--70grad{--una-exit-rotate:-70grad;} + .spin-out--70rad{--una-exit-rotate:-70rad;} + .spin-out--70turn{--una-exit-rotate:-70turn;} + .spin-out--80deg{--una-exit-rotate:-80deg;} + .spin-out--80grad{--una-exit-rotate:-80grad;} + .spin-out--80rad{--una-exit-rotate:-80rad;} + .spin-out--80turn{--una-exit-rotate:-80turn;} + .spin-out--90deg{--una-exit-rotate:-90deg;} + .spin-out--90grad{--una-exit-rotate:-90grad;} + .spin-out--90rad{--una-exit-rotate:-90rad;} + .spin-out--90turn{--una-exit-rotate:-90turn;} + .spin-out-100deg{--una-exit-rotate:100deg;} + .spin-out-100grad{--una-exit-rotate:100grad;} + .spin-out-100rad{--una-exit-rotate:100rad;} + .spin-out-100turn{--una-exit-rotate:100turn;} + .spin-out-10deg{--una-exit-rotate:10deg;} + .spin-out-10grad{--una-exit-rotate:10grad;} + .spin-out-10rad{--una-exit-rotate:10rad;} + .spin-out-10turn{--una-exit-rotate:10turn;} + .spin-out-110deg{--una-exit-rotate:110deg;} + .spin-out-110grad{--una-exit-rotate:110grad;} + .spin-out-110rad{--una-exit-rotate:110rad;} + .spin-out-110turn{--una-exit-rotate:110turn;} + .spin-out-120deg{--una-exit-rotate:120deg;} + .spin-out-120grad{--una-exit-rotate:120grad;} + .spin-out-120rad{--una-exit-rotate:120rad;} + .spin-out-120turn{--una-exit-rotate:120turn;} + .spin-out-130deg{--una-exit-rotate:130deg;} + .spin-out-130grad{--una-exit-rotate:130grad;} + .spin-out-130rad{--una-exit-rotate:130rad;} + .spin-out-130turn{--una-exit-rotate:130turn;} + .spin-out-140deg{--una-exit-rotate:140deg;} + .spin-out-140grad{--una-exit-rotate:140grad;} + .spin-out-140rad{--una-exit-rotate:140rad;} + .spin-out-140turn{--una-exit-rotate:140turn;} + .spin-out-150deg{--una-exit-rotate:150deg;} + .spin-out-150grad{--una-exit-rotate:150grad;} + .spin-out-150rad{--una-exit-rotate:150rad;} + .spin-out-150turn{--una-exit-rotate:150turn;} + .spin-out-160deg{--una-exit-rotate:160deg;} + .spin-out-160grad{--una-exit-rotate:160grad;} + .spin-out-160rad{--una-exit-rotate:160rad;} + .spin-out-160turn{--una-exit-rotate:160turn;} + .spin-out-170deg{--una-exit-rotate:170deg;} + .spin-out-170grad{--una-exit-rotate:170grad;} + .spin-out-170rad{--una-exit-rotate:170rad;} + .spin-out-170turn{--una-exit-rotate:170turn;} + .spin-out-180deg{--una-exit-rotate:180deg;} + .spin-out-180grad{--una-exit-rotate:180grad;} + .spin-out-180rad{--una-exit-rotate:180rad;} + .spin-out-180turn{--una-exit-rotate:180turn;} + .spin-out-190deg{--una-exit-rotate:190deg;} + .spin-out-190grad{--una-exit-rotate:190grad;} + .spin-out-190rad{--una-exit-rotate:190rad;} + .spin-out-190turn{--una-exit-rotate:190turn;} + .spin-out-200deg{--una-exit-rotate:200deg;} + .spin-out-200grad{--una-exit-rotate:200grad;} + .spin-out-200rad{--una-exit-rotate:200rad;} + .spin-out-200turn{--una-exit-rotate:200turn;} + .spin-out-20deg{--una-exit-rotate:20deg;} + .spin-out-20grad{--una-exit-rotate:20grad;} + .spin-out-20rad{--una-exit-rotate:20rad;} + .spin-out-20turn{--una-exit-rotate:20turn;} + .spin-out-30deg{--una-exit-rotate:30deg;} + .spin-out-30grad{--una-exit-rotate:30grad;} + .spin-out-30rad{--una-exit-rotate:30rad;} + .spin-out-30turn{--una-exit-rotate:30turn;} + .spin-out-40deg{--una-exit-rotate:40deg;} + .spin-out-40grad{--una-exit-rotate:40grad;} + .spin-out-40rad{--una-exit-rotate:40rad;} + .spin-out-40turn{--una-exit-rotate:40turn;} + .spin-out-50deg{--una-exit-rotate:50deg;} + .spin-out-50grad{--una-exit-rotate:50grad;} + .spin-out-50rad{--una-exit-rotate:50rad;} + .spin-out-50turn{--una-exit-rotate:50turn;} + .spin-out-60deg{--una-exit-rotate:60deg;} + .spin-out-60grad{--una-exit-rotate:60grad;} + .spin-out-60rad{--una-exit-rotate:60rad;} + .spin-out-60turn{--una-exit-rotate:60turn;} + .spin-out-70deg{--una-exit-rotate:70deg;} + .spin-out-70grad{--una-exit-rotate:70grad;} + .spin-out-70rad{--una-exit-rotate:70rad;} + .spin-out-70turn{--una-exit-rotate:70turn;} + .spin-out-80deg{--una-exit-rotate:80deg;} + .spin-out-80grad{--una-exit-rotate:80grad;} + .spin-out-80rad{--una-exit-rotate:80rad;} + .spin-out-80turn{--una-exit-rotate:80turn;} + .spin-out-90deg{--una-exit-rotate:90deg;} + .spin-out-90grad{--una-exit-rotate:90grad;} + .spin-out-90rad{--una-exit-rotate:90rad;} + .spin-out-90turn{--una-exit-rotate:90turn;}" + `) + }) + + + it(`should not use any unit for "0"`, async () => { + const classnames = [ + 'spin-out-0', + 'spin-out-0deg', + 'spin-out-0rad', + 'spin-out-0grad', + 'spin-out-0turn' + ] + + const { matched, css } = await uno.generate(classnames) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .spin-out-0, + .spin-out-0deg, + .spin-out-0grad, + .spin-out-0rad, + .spin-out-0turn{--una-exit-rotate:0;}" + `) + }) + }) + + + describe('css variable', () => { + it(`should handle css variables`, async () => { + const classnames = CSS_VARIABLES.map(i => `spin-out-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .spin-out-\\\\$foo{--una-exit-rotate:var(--foo);} + .spin-out-\\\\$foo-bar{--una-exit-rotate:var(--foo-bar);} + .spin-out-\\\\$fooBar{--una-exit-rotate:var(--fooBar);}" + `) + }) + }) + }) +}) diff --git a/test/utils/index.ts b/test/utils/index.ts new file mode 100644 index 0000000..2ed6797 --- /dev/null +++ b/test/utils/index.ts @@ -0,0 +1,17 @@ +import { createGenerator } from '@unocss/core' +import { presetUno } from 'unocss' +import presetAnimations from '@/index' +import type { UnoGenerator } from '@unocss/core' +import type { Theme } from '@unocss/preset-mini' + + +export const generator = (theme?: Theme): UnoGenerator => createGenerator({ + presets: [ + presetUno({ preflight: false }), + presetAnimations() + ], + theme +}) + + +export const uno = generator() diff --git a/test/zoom.test.ts b/test/zoom.test.ts new file mode 100644 index 0000000..91dd37a --- /dev/null +++ b/test/zoom.test.ts @@ -0,0 +1,290 @@ +import { describe, it, expect } from 'vitest' +import { CSS_VARIABLE_PREFIX } from '@/constants' +import { CSS_VARIABLES, DECIMALS, FRACTIONS, INTEGERS } from '~/data' +import { uno } from '~/utils' + + +describe('zoom animation', () => { + describe('zoom-in', () => { + it(`should generate "${CSS_VARIABLE_PREFIX}-enter-scale" css variable and default to "0"`, async () => { + const { css } = await uno.generate('zoom-in') + + expect(css).toContain(`.zoom-in{${CSS_VARIABLE_PREFIX}-enter-scale:0;}`) + }) + + + describe('percentage', () => { + it(`should covert any percentages including negative`, async () => { + const classnames = INTEGERS.map(i => `zoom-in-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .zoom-in--10{--una-enter-scale:-0.1;} + .zoom-in--100{--una-enter-scale:-1;} + .zoom-in--110{--una-enter-scale:-1.1;} + .zoom-in--120{--una-enter-scale:-1.2;} + .zoom-in--130{--una-enter-scale:-1.3;} + .zoom-in--140{--una-enter-scale:-1.4;} + .zoom-in--150{--una-enter-scale:-1.5;} + .zoom-in--160{--una-enter-scale:-1.6;} + .zoom-in--170{--una-enter-scale:-1.7;} + .zoom-in--180{--una-enter-scale:-1.8;} + .zoom-in--190{--una-enter-scale:-1.9;} + .zoom-in--20{--una-enter-scale:-0.2;} + .zoom-in--200{--una-enter-scale:-2;} + .zoom-in--30{--una-enter-scale:-0.3;} + .zoom-in--40{--una-enter-scale:-0.4;} + .zoom-in--50{--una-enter-scale:-0.5;} + .zoom-in--60{--una-enter-scale:-0.6;} + .zoom-in--70{--una-enter-scale:-0.7;} + .zoom-in--80{--una-enter-scale:-0.8;} + .zoom-in--90{--una-enter-scale:-0.9;} + .zoom-in-0{--una-enter-scale:0;} + .zoom-in-10{--una-enter-scale:0.1;} + .zoom-in-100{--una-enter-scale:1;} + .zoom-in-110{--una-enter-scale:1.1;} + .zoom-in-120{--una-enter-scale:1.2;} + .zoom-in-130{--una-enter-scale:1.3;} + .zoom-in-140{--una-enter-scale:1.4;} + .zoom-in-150{--una-enter-scale:1.5;} + .zoom-in-160{--una-enter-scale:1.6;} + .zoom-in-170{--una-enter-scale:1.7;} + .zoom-in-180{--una-enter-scale:1.8;} + .zoom-in-190{--una-enter-scale:1.9;} + .zoom-in-20{--una-enter-scale:0.2;} + .zoom-in-200{--una-enter-scale:2;} + .zoom-in-30{--una-enter-scale:0.3;} + .zoom-in-40{--una-enter-scale:0.4;} + .zoom-in-50{--una-enter-scale:0.5;} + .zoom-in-60{--una-enter-scale:0.6;} + .zoom-in-70{--una-enter-scale:0.7;} + .zoom-in-80{--una-enter-scale:0.8;} + .zoom-in-90{--una-enter-scale:0.9;}" + `) + }) + + + it(`should also convert decimals including negative`, async () => { + const classnames = DECIMALS.map(i => `zoom-in-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .zoom-in--0\\\\.1{--una-enter-scale:-0.001;} + .zoom-in--10\\\\.1{--una-enter-scale:-0.101;} + .zoom-in--180\\\\.37{--una-enter-scale:-1.8037;} + .zoom-in--199\\\\.9{--una-enter-scale:-1.999;} + .zoom-in--52\\\\.1{--una-enter-scale:-0.521;} + .zoom-in--66\\\\.66{--una-enter-scale:-0.6666;} + .zoom-in-0\\\\.1{--una-enter-scale:0.001;} + .zoom-in-10\\\\.1{--una-enter-scale:0.101;} + .zoom-in-180\\\\.37{--una-enter-scale:1.8037;} + .zoom-in-199\\\\.9{--una-enter-scale:1.999;} + .zoom-in-52\\\\.1{--una-enter-scale:0.521;} + .zoom-in-66\\\\.66{--una-enter-scale:0.6666;} + .zoom-in-99\\\\.9{--una-enter-scale:0.999;}" + `) + }) + }) + + + describe('fraction', () => { + it(`should covert any fractions including negative`, async () => { + const classnames = FRACTIONS.map(i => `zoom-in-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .zoom-in--1\\\\/3{--una-enter-scale:-33.3333333333%;} + .zoom-in--1\\\\/4{--una-enter-scale:-25%;} + .zoom-in--1\\\\/6{--una-enter-scale:-16.6666666667%;} + .zoom-in--2\\\\/3{--una-enter-scale:-66.6666666667%;} + .zoom-in--3\\\\/4{--una-enter-scale:-75%;} + .zoom-in--5\\\\/6{--una-enter-scale:-83.3333333333%;} + .zoom-in-1\\\\/3{--una-enter-scale:33.3333333333%;} + .zoom-in-1\\\\/4{--una-enter-scale:25%;} + .zoom-in-1\\\\/6{--una-enter-scale:16.6666666667%;} + .zoom-in-2\\\\/3{--una-enter-scale:66.6666666667%;} + .zoom-in-3\\\\/4{--una-enter-scale:75%;} + .zoom-in-5\\\\/6{--una-enter-scale:83.3333333333%;}" + `) + }) + + + it(`should convert "full" to "100%`, async () => { + const { css } = await uno.generate('zoom-in-full') + + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .zoom-in-full{--una-enter-scale:100%;}" + `) + }) + }) + + + describe('css variable', () => { + it(`should handle css variables`, async () => { + const classnames = CSS_VARIABLES.map(i => `zoom-in-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .zoom-in-\\\\$foo{--una-enter-scale:var(--foo);} + .zoom-in-\\\\$foo-bar{--una-enter-scale:var(--foo-bar);} + .zoom-in-\\\\$fooBar{--una-enter-scale:var(--fooBar);}" + `) + }) + }) + }) + + + describe('zoom-out', () => { + it(`should generate "${CSS_VARIABLE_PREFIX}-exit-scale" css variable and default to "0"`, async () => { + const { css } = await uno.generate('zoom-out') + + expect(css).toContain(`.zoom-out{${CSS_VARIABLE_PREFIX}-exit-scale:0;}`) + }) + + + describe('percentage', () => { + it(`should covert any percentages including negative`, async () => { + const classnames = INTEGERS.map(i => `zoom-out-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .zoom-out--10{--una-exit-scale:-0.1;} + .zoom-out--100{--una-exit-scale:-1;} + .zoom-out--110{--una-exit-scale:-1.1;} + .zoom-out--120{--una-exit-scale:-1.2;} + .zoom-out--130{--una-exit-scale:-1.3;} + .zoom-out--140{--una-exit-scale:-1.4;} + .zoom-out--150{--una-exit-scale:-1.5;} + .zoom-out--160{--una-exit-scale:-1.6;} + .zoom-out--170{--una-exit-scale:-1.7;} + .zoom-out--180{--una-exit-scale:-1.8;} + .zoom-out--190{--una-exit-scale:-1.9;} + .zoom-out--20{--una-exit-scale:-0.2;} + .zoom-out--200{--una-exit-scale:-2;} + .zoom-out--30{--una-exit-scale:-0.3;} + .zoom-out--40{--una-exit-scale:-0.4;} + .zoom-out--50{--una-exit-scale:-0.5;} + .zoom-out--60{--una-exit-scale:-0.6;} + .zoom-out--70{--una-exit-scale:-0.7;} + .zoom-out--80{--una-exit-scale:-0.8;} + .zoom-out--90{--una-exit-scale:-0.9;} + .zoom-out-0{--una-exit-scale:0;} + .zoom-out-10{--una-exit-scale:0.1;} + .zoom-out-100{--una-exit-scale:1;} + .zoom-out-110{--una-exit-scale:1.1;} + .zoom-out-120{--una-exit-scale:1.2;} + .zoom-out-130{--una-exit-scale:1.3;} + .zoom-out-140{--una-exit-scale:1.4;} + .zoom-out-150{--una-exit-scale:1.5;} + .zoom-out-160{--una-exit-scale:1.6;} + .zoom-out-170{--una-exit-scale:1.7;} + .zoom-out-180{--una-exit-scale:1.8;} + .zoom-out-190{--una-exit-scale:1.9;} + .zoom-out-20{--una-exit-scale:0.2;} + .zoom-out-200{--una-exit-scale:2;} + .zoom-out-30{--una-exit-scale:0.3;} + .zoom-out-40{--una-exit-scale:0.4;} + .zoom-out-50{--una-exit-scale:0.5;} + .zoom-out-60{--una-exit-scale:0.6;} + .zoom-out-70{--una-exit-scale:0.7;} + .zoom-out-80{--una-exit-scale:0.8;} + .zoom-out-90{--una-exit-scale:0.9;}" + `) + }) + + + it(`should also convert decimals including negative`, async () => { + const classnames = DECIMALS.map(i => `zoom-out-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .zoom-out--0\\\\.1{--una-exit-scale:-0.001;} + .zoom-out--10\\\\.1{--una-exit-scale:-0.101;} + .zoom-out--180\\\\.37{--una-exit-scale:-1.8037;} + .zoom-out--199\\\\.9{--una-exit-scale:-1.999;} + .zoom-out--52\\\\.1{--una-exit-scale:-0.521;} + .zoom-out--66\\\\.66{--una-exit-scale:-0.6666;} + .zoom-out-0\\\\.1{--una-exit-scale:0.001;} + .zoom-out-10\\\\.1{--una-exit-scale:0.101;} + .zoom-out-180\\\\.37{--una-exit-scale:1.8037;} + .zoom-out-199\\\\.9{--una-exit-scale:1.999;} + .zoom-out-52\\\\.1{--una-exit-scale:0.521;} + .zoom-out-66\\\\.66{--una-exit-scale:0.6666;} + .zoom-out-99\\\\.9{--una-exit-scale:0.999;}" + `) + }) + }) + + + describe('fraction', () => { + it(`should covert any fractions including negative`, async () => { + const classnames = FRACTIONS.map(i => `zoom-out-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .zoom-out--1\\\\/3{--una-exit-scale:-33.3333333333%;} + .zoom-out--1\\\\/4{--una-exit-scale:-25%;} + .zoom-out--1\\\\/6{--una-exit-scale:-16.6666666667%;} + .zoom-out--2\\\\/3{--una-exit-scale:-66.6666666667%;} + .zoom-out--3\\\\/4{--una-exit-scale:-75%;} + .zoom-out--5\\\\/6{--una-exit-scale:-83.3333333333%;} + .zoom-out-1\\\\/3{--una-exit-scale:33.3333333333%;} + .zoom-out-1\\\\/4{--una-exit-scale:25%;} + .zoom-out-1\\\\/6{--una-exit-scale:16.6666666667%;} + .zoom-out-2\\\\/3{--una-exit-scale:66.6666666667%;} + .zoom-out-3\\\\/4{--una-exit-scale:75%;} + .zoom-out-5\\\\/6{--una-exit-scale:83.3333333333%;}" + `) + }) + + + it(`should convert "full" to "100%`, async () => { + const { css } = await uno.generate('zoom-out-full') + + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .zoom-out-full{--una-exit-scale:100%;}" + `) + }) + }) + + + describe('css variable', () => { + it(`should handle css variables`, async () => { + const classnames = CSS_VARIABLES.map(i => `zoom-out-${i}`) + + const { matched, css } = await uno.generate(classnames.join(' ')) + + expect(matched).toStrictEqual(new Set(classnames)) + expect(css).toMatchInlineSnapshot(` + "/* layer: default */ + .zoom-out-\\\\$foo{--una-exit-scale:var(--foo);} + .zoom-out-\\\\$foo-bar{--una-exit-scale:var(--foo-bar);} + .zoom-out-\\\\$fooBar{--una-exit-scale:var(--fooBar);}" + `) + }) + }) + }) +}) diff --git a/tsconfig.json b/tsconfig.json index 87e17c0..72afa91 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,12 @@ "esModuleInterop": true, "skipLibCheck": true, "noUncheckedIndexedAccess": true, - "resolveJsonModule": true + "resolveJsonModule": true, + "baseUrl": ".", + "paths": { + "@/*": ["src/*"], + "~/*": ["test/*"] + } }, "include": [ "**/*.ts", diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..f5823df --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,12 @@ +import { fileURLToPath, URL } from 'node:url' +import { defineConfig } from 'vitest/config' + + +export default defineConfig({ + resolve: { + alias: { + '@': fileURLToPath(new URL('src', import.meta.url)), + '~': fileURLToPath(new URL('test', import.meta.url)) + } + } +})