Skip to content

Commit

Permalink
Core package tests (#1)
Browse files Browse the repository at this point in the history
* Init tests

* Add more tests

* Tests

* Add coverage
  • Loading branch information
drozdzynski authored Aug 21, 2023
1 parent 8b04cc4 commit 1a437f8
Show file tree
Hide file tree
Showing 21 changed files with 1,997 additions and 95 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Tests

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:
runs-on: ubuntu-20.04
strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- uses: actions/cache@v3
id: yarn-cache
with:
path: .yarn/cache
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install Dependencies
run: yarn install
- name: Run tests
run: yarn test -- --ci --coverage
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ node_modules
.yarn/local
.pnp.*
**/dist/*
**/.turbo/*
**/.turbo/*
**/coverage/*
Binary file modified .yarn/install-state.gz
Binary file not shown.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"eslint": "^8.42.0",
"prettier": "^3.0.0",
"storybook": "^7.0.23",
"turbo": "^1.10.3",
"turbo": "^1.10.12",
"typescript": "^5.1.3",
"vite": "^4.3.9",
"wait-on": "^7.0.1"
Expand Down
6 changes: 6 additions & 0 deletions packages/core/jest.client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { JSDOM } from "jsdom"
const dom = new JSDOM()
global.document = dom.window.document
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
global.window = dom.window
13 changes: 13 additions & 0 deletions packages/core/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export default {
preset: 'ts-jest',
testEnvironment: 'node',
setupFiles: ['./jest.client.ts'],
coverageThreshold: {
global: {
branches: 90,
functions: 90,
lines: 90,
statements: 90,
},
},
}
5 changes: 5 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,26 @@
"scripts": {
"build": "rollup --config --bundleConfigAsCjs",
"dev": "rollup --config --bundleConfigAsCjs --watch",
"test": "jest",
"wait": "wait-on dist/teiler-core.cjs.js"
},
"dependencies": {
"stylis": "^4.2.0"
},
"devDependencies": {
"@jest/globals": "^29.6.2",
"@rollup/plugin-commonjs": "^25.0.1",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.1.0",
"@types/stylis": "^4.2.0",
"esbuild": "^0.18.2",
"jest": "^29.6.2",
"jsdom": "^22.1.0",
"rollup": "^3.25.1",
"rollup-plugin-dts": "^5.3.0",
"rollup-plugin-esbuild": "^5.0.0",
"rollup-plugin-terser": "^7.0.2",
"ts-jest": "^29.1.1",
"typescript": "^5.1.3"
}
}
63 changes: 63 additions & 0 deletions packages/core/src/css.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { describe, expect, test } from '@jest/globals'
import { stylis, compile } from './css'
import { Style } from '.'

describe('stylis', () => {
test('should return an empty array if the CSS string is empty', () => {
const css = ''
const results = stylis(css)
expect(results).toHaveLength(0)
})

test('should return an array of CSS strings with comments removed', () => {
const css = '/* This is a comment */ p { color: red; } /* This is another comment */'
const results = stylis(css)
expect(results).toHaveLength(1)
expect(results.at(0)).toBe('p{color:red;}')
})

test('should return button with hover from nasted selector ', () => {
const css = 'button { color: blue; &:hover: { color: red; } }'
const results = stylis(css)
expect(results).toHaveLength(2)
expect(results).toEqual(['button{color:blue;}', 'button:hover:{color:red;}'])
})
})

describe('compile', () => {
test('without props', () => {
const style: Style<{}> = [['color: blue;'], []]
const compiled = compile<{}>([style], {})

expect(compiled).toEqual([{ id: '1r77qux', name: 'teiler-1r77qux', css: 'color: blue;' }])
})

test('with props', () => {
type Props = { color: string }

const style: Style<Props> = [['color: ', ';'], [({ color }) => color]]
const compiled = compile<Props>([style], { color: 'red' })

expect(compiled).toEqual([{ id: 'wq229y', name: 'teiler-wq229y', css: 'color: red;' }])
})

test('with object', () => {
const keyframes = {
css: '@keyframes test { from { background-color: yellow; } to { background-color: red; } }',
id: '14uknit',
name: 'teiler-keyframes-14uknit',
}

const style: Style<{}> = [['animation: ', ' 5s;'], [keyframes]]
const compiled = compile<{}>([style], {})

expect(compiled).toEqual([
keyframes,
{
id: 'd18jjz',
name: 'teiler-d18jjz',
css: 'animation: teiler-keyframes-14uknit 5s;',
},
])
})
})
26 changes: 26 additions & 0 deletions packages/core/src/hash.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { describe, expect, test } from '@jest/globals'
import hash from './hash'

describe('hash', () => {
test('create hash', () => {
const styles = `
color: red;
background: blue;
`

const generated = hash(styles)
expect(generated).toEqual('1a6449z')
})

test('compare hashe of styles', () => {
const styles = `
color: red;
background: blue;
`

const hash1 = hash(styles)
const hash2 = hash(styles)

expect(hash1).toEqual(hash2)
})
})
5 changes: 3 additions & 2 deletions packages/core/src/hash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ export default function hash(str: string): string {

l -= 4
++i
} // forgive existing code
}

/* eslint-disable no-fallthrough */ switch (l) {
/* eslint-disable no-fallthrough */
switch (l) {
case 3:
h ^= (str.charCodeAt(i + 2) & 0xff) << 16
case 2:
Expand Down
114 changes: 114 additions & 0 deletions packages/core/src/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import type { Compile, Style, TeilerComponent } from '.'

import { describe, jest, expect, test } from '@jest/globals'
import styled, { component, global, keyframes, createStyleSheet } from '.'

const createComponent = <Target, Props>(compile: Compile, tag: Target, styles: Array<Style<Props>>): TeilerComponent<Target, Props> => {
return {
tag,
styles,
}
}

describe('styled', () => {
test('should create component', () => {
const createComponentBinded = createComponent.bind(null, null, 'div')
const template = ['color: red;']
const test = jest.fn(styled)

test(createComponentBinded, template)

expect(test).toHaveReturnedWith({ styles: [[['color: red;'], []]], tag: 'div' })
})

test('should extend component', () => {
const createComponentBinded = createComponent.bind(null, null, 'div')
const template = ['background: blue;']
const component: TeilerComponent<'div', {}> = { tag: 'div', styles: [[['color: red;'], []]] }

const extend = styled(createComponentBinded, component)

type Callable = Extract<typeof extend, Function>

const test = jest.fn(extend as Callable)

test(template)

expect(test).toHaveReturnedWith({
styles: [
[['color: red;'], []],
[['background: blue;'], []],
],
tag: 'div',
})
})
})

describe('component', () => {
test('should create style from styles', () => {
const styleSheet = createStyleSheet({})
const test = jest.fn(component)

test(styleSheet, [[['color: red;'], []]], [])

expect(test).toHaveReturnedWith(['teiler-wq229y'])
})

test('should create style from styles with props', () => {
const styleSheet = createStyleSheet({})
const test = jest.fn(component)

test(styleSheet, [[['color: ', ';'], [({ color }) => color]]], [{ color: 'red' }])

expect(test).toHaveReturnedWith(['teiler-10upe3l'])
})
})

describe('global', () => {
test('should create style from styles', () => {
const styleSheet = createStyleSheet({})
const test = jest.fn(global)

test(styleSheet, [[['body { color: red; }'], []]], {})

expect(test).toHaveReturnedWith(undefined)
expect(styleSheet.dump()).toContain(' body{color:red;}')
})

test('should create style from styles with props', () => {
const styleSheet = createStyleSheet({})
const test = jest.fn(global)

test(styleSheet, [[['body { color: ', '; }'], [({ color }) => color]]], { color: 'blue' })

expect(test).toHaveReturnedWith(undefined)
expect(styleSheet.dump()).toContain(' body{color:blue;}')
})
})

describe('keyframes', () => {
test('should create a keyframes definition with the given strings and properties', () => {
const keyframesDefinition = keyframes`from { background-color: red; } to { background-color: green; }`

expect(keyframesDefinition).toStrictEqual({
css: `@keyframes teiler-keyframes-1ep7axc { from { background-color: red; } to { background-color: green; } }`,
id: '1ep7axc',
name: 'teiler-keyframes-1ep7axc',
})
})

test('should allow passing properties to the keyframes definition', () => {
const props = {
from: 'yellow',
to: 'red',
}

const keyframesDefinition = keyframes`from { background-color: ${props.from}; } to { background-color: ${props.to}; }`

expect(keyframesDefinition).toEqual({
css: '@keyframes teiler-keyframes-14uknit { from { background-color: yellow; } to { background-color: red; } }',
id: '14uknit',
name: 'teiler-keyframes-14uknit',
})
})
})
16 changes: 8 additions & 8 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import type { Sheet } from './sheet'

import { compile, stylis } from './css'
import createStyleSheet from './sheet'
import { pattern, sew } from './pattern'

type Expression<Props> = (props: Props) => string | boolean
type StyleDefinition = {
Expand All @@ -20,20 +18,20 @@ type TeilerComponent<Target, Props> = {
}

type CreateCallback<Props, Type extends TeilerComponent<Target, Props>> = (styles: Array<Style<Props>>) => Type
type ExtendCallback<Props, Type extends TeilerComponent<Target, Props>> = (string: TemplateStringsArray, ...properties: Properties<Props>[]) => Type
type ExtendCallback<Props, Type extends TeilerComponent<Target, Props>> = (string: ReadonlyArray<string>, ...properties: Properties<Props>[]) => Type

function styled<Props, Type extends TeilerComponent<Target, Props>>(
createComponent: CreateCallback<Props, Type>,
stringOrBinded: TeilerComponent<Target, Props> | TemplateStringsArray,
stringOrBinded: TeilerComponent<Target, Props> | ReadonlyArray<string>,
...properties: Properties<Props>[]
): ExtendCallback<Props, Type> | Type {
if (Array.isArray(stringOrBinded)) {
const strings = stringOrBinded as TemplateStringsArray
const strings = stringOrBinded as ReadonlyArray<string>
const style: Style<Props> = [Array.from(strings), properties]
return createComponent([style])
} else {
const binded = stringOrBinded as TeilerComponent<Target, Props>
return (strings: TemplateStringsArray, ...properties: Expression<Props>[]) => {
return (strings: ReadonlyArray<string>, ...properties: Expression<Props>[]) => {
const style: Style<Props> = [Array.from(strings), properties]
return createComponent([...binded.styles, style])
}
Expand All @@ -58,7 +56,7 @@ function global<Props>(sheet: Sheet, styles: Array<Style<Props>>, props: Props):
})
}

function keyframes(strings: TemplateStringsArray, ...properties: Raw[]): StyleDefinition {
function keyframes(strings: ReadonlyArray<string>, ...properties: Raw[]): StyleDefinition {
const style: Style<{}> = [Array.from(strings), properties]

const [{id, css}] = compile([style], {})
Expand All @@ -68,5 +66,7 @@ function keyframes(strings: TemplateStringsArray, ...properties: Raw[]): StyleDe
}

export type { Compile, Properties, Sheet, Style, StyleDefinition, TeilerComponent, Target }
export { component, global, keyframes, createStyleSheet, pattern, sew }
export { component, global, keyframes }
export { default as createStyleSheet } from './sheet'
export { pattern, sew } from './pattern'
export default styled
Loading

0 comments on commit 1a437f8

Please sign in to comment.