Passed
Push — main ( fd6a98...c16722 )
by Andrii
02:18
created

__tests__/readme.spec.tsx   A

Complexity

Total Complexity 6
Complexity/F 1.2

Size

Lines of Code 261
Function Count 5

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 6
eloc 211
mnd 1
bc 1
fnc 5
dl 0
loc 261
rs 10
bpm 0.2
cpm 1.2
noi 0
c 0
b 0
f 0

3 Functions

Rating   Name   Duplication   Size   Complexity  
A readme.spec.tsx ➔ FormButtons 0 18 1
A readme.spec.tsx ➔ DialogButton 0 8 1
A readme.spec.tsx ➔ Button 0 21 2
1
import React from "react"
2
import expectRender from "../expect-to-same-render"
3
import classNaming, { classBeming, ClassNamed, Undefineds } from "../src"
4
import type {ClassHash, ClassNamesProperty} from "../src"
5
// import css_module from "./button.module.css"
6
const css_module = {button: "BTN"}
7
8
it("Basic usage", () => {
9
  type Props = {
10
    isValid: boolean
11
    readOnly: boolean
12
  }
13
14
  // isValid = false, readOnly = false
15
  function FormButtons({isValid, readOnly}: Props) {
16
    const cssClasses = classNaming()
17
    const buttonClass = cssClasses({"button": true}) // "button"
18
    
19
    return <>
20
      <button {
21
        ...buttonClass // className="button" 
22
      }>Close</button>
23
      <button type="reset" {
24
        ...buttonClass({"button--disabled": readOnly}) // className="button"
25
      }>Reset</button> 
26
                        {/* className="button_submit button button--disabled" */}
27
      <button type="submit" className={`button_submit ${
28
        buttonClass({"button--disabled": readOnly || !isValid}) // "button button--disabled"
29
      }`}>Submit</button> 
30
    </>
31
  }  
32
33
  expectRender(
34
    <FormButtons isValid={false} readOnly={false} />
35
  ).toSame(<>
36
    <button className="button">Close</button>
37
    <button type="reset" className="button">Reset</button>
38
    <button type="submit" className="button_submit button button--disabled">Submit</button>
39
  </>)
40
})
41
42
it("Strict type", () => {
43
  type Props = {readOnly?: boolean}
44
  const {readOnly} = {} as Props
45
  const cssClasses = classNaming()
46
  const disabling = cssClasses({
47
    //@ts-expect-error Type 'boolean | undefined' is not assignable to type 'boolean'
48
    "button--disabled": readOnly
49
  })
50
51
  expect({...disabling}).toStrictEqual({className: "button--disabled"})
52
})
53
54
it("Single source of truth", () => {
55
  const cssClasses = classNaming()
56
  const isValidClass = cssClasses({"button--disabled": /* !isValid */ false })
57
  // ... more code
58
  const buttonClass = isValidClass({button: true})
59
  // ... more code
60
  const disablingClass = buttonClass({
61
    //@ts-expect-error Type 'boolean' is not assignable to type 'never'
62
    "button--disabled": true
63
  })
64
  
65
  expect({...disablingClass}).toStrictEqual({
66
    className: "button button--disabled"
67
  })
68
})
69
70
it("Declare own component's CSS classes", () => {
71
  type MyClassNames = ClassNamesProperty<{
72
    button: ClassHash
73
    button_submit: ClassHash
74
    "button--disabled": ClassHash
75
  }>
76
  type Props = {
77
    isValid: boolean
78
    readOnly: boolean
79
  }
80
81
  // isValid = false, readOnly = false
82
  function FormButtons({isValid, readOnly}: Props) {
83
    const cssClasses = classNaming<MyClassNames>()
84
    const buttonClass = cssClasses({button: true})
85
    
86
    return <>
87
      <button {
88
        ...buttonClass // className="button" 
89
      }>Close</button>
90
      <button type="reset" {
91
        ...buttonClass({
92
        "button--disabled": readOnly
93
      }) // className="button"
94
      }>Reset</button> 
95
      <button type="submit" {
96
        ...buttonClass({
97
          "button_submit": true,
98
          "button--disabled": readOnly || !isValid
99
        }) // className="button button_submit button--disabled"
100
      }>Submit</button> 
101
    </>
102
  }  
103
104
  expectRender(
105
    <FormButtons isValid={false} readOnly={false} />
106
  ).toSame(<>
107
    <button className="button">Close</button>
108
    <button type="reset" className="button">Reset</button>
109
    <button type="submit" className="button button_submit button--disabled">Submit</button>
110
  </>)
111
})
112
113
it("Using ClassHash", () => {
114
  // CSS-module
115
  const { button } = css_module
116
117
  // Module simulation
118
  type CssModuleSimulation = { button_submit: ClassHash }
119
  const { button_submit } = {} as CssModuleSimulation
120
  
121
  type MyClassNames = ClassNamesProperty<
122
    typeof css_module &
123
    CssModuleSimulation &
124
    {
125
      "button--disabled": ClassHash
126
    }
127
  >
128
  type Props = {
129
    isValid: boolean
130
    readOnly: boolean
131
  }
132
133
  // isValid = false, readOnly = false
134
  function FormButtons({isValid, readOnly}: Props) {
135
    const cssClasses = classNaming<MyClassNames>()
136
    const buttonClass = cssClasses({ button })
137
    
138
    return <>
139
      <button {
140
        ...buttonClass // className="BTN" 
141
      }>Close</button>
142
      <button type="reset" {
143
        ...buttonClass({
144
          "button--disabled": readOnly
145
      }) // className="BTN"
146
      }>Reset</button> 
147
      <button type="submit" {...buttonClass({
148
        button_submit,
149
        "button--disabled": readOnly || !isValid
150
      }) // "BTN button_submit button--disabled"
151
      }>Submit</button> 
152
    </>
153
  }  
154
155
  expectRender(
156
    <FormButtons isValid={false} readOnly={false} />
157
  ).toSame(<>
158
    <button className="BTN">Close</button>
159
    <button type="reset" className="BTN">Reset</button>
160
    <button type="submit" className="BTN button_submit button--disabled">Submit</button>
161
  </>)
162
})
163
164
it("bem leaf", () => {
165
  type Props = ClassNamesProperty<MaterialClasses>
166
  & { focused?: boolean }
167
168
  function DialogButton({focused}: Props) {
169
    const bem = classBeming<Props>()
170
  
171
    return <button {...bem({
172
      dialog__button: true,
173
      button: {type: "raised"},
174
      ripple: focused && "background-focused"
175
    })}/>
176
  }
177
178
  
179
  const props = {focused: true} as Props
180
181
  expectRender(
182
    <DialogButton {...props}/>
183
  ).toSame(
184
    <button className="dialog__button button button--type--raised ripple ripple--background-focused" />
185
  )
186
})
187
188
describe("bem from https://material.io/components/buttons/web#contained-button", () => {
189
  const CONSTS = {ripple: "ripple-upgraded", icon: {"material-icons": true}} as const
190
191
  type Props = ClassNamed & ClassNamesProperty<MaterialClasses>
192
  & { focused?: boolean; clicking?: boolean }
193
194
  const {ripple, icon} = CONSTS
195
  const {
196
    button__icon,
197
    button__label,
198
    button__ripple
199
  } = {} as Undefineds<MaterialClasses>
200
201
  function Button(props: Props) {
202
    const {
203
      clicking,
204
      focused = false,
205
    } = props
206
207
    const bem = classBeming(props)
208
209
    return <button {...bem(true, {
210
      button: "raised",
211
      [ripple]: [
212
        "unbounded",
213
        focused && "background-focused",
214
        clicking ? "foreground-activation" : clicking === false && "foreground-deactivation"
215
      ]
216
    })}>
217
      <span  {...bem({button__ripple})}/>
218
      <i  {...bem({button__icon, ...icon})}>bookmark</i>
219
      <span  {...bem({button__label})}>Contained Button plus Icon</span>
220
    </button>
221
  }
222
223
  expectRender(
224
    <Button className="dialog__button" clicking={false} focused={true} classnames={{} as MaterialClasses}/>
225
  ).toSame(
226
    <button className="dialog__button button button--raised ripple-upgraded ripple-upgraded--unbounded ripple-upgraded--background-focused ripple-upgraded--foreground-deactivation">
227
      <span className="button__ripple"/>
228
      <i className="button__icon material-icons">bookmark</i>
229
      <span className="button__label">Contained Button plus Icon</span>
230
    </button>
231
  )
232
})
233
234
type MaterialClasses = {
235
  "material-icons": ClassHash
236
  ripple: ClassHash
237
  "ripple--bounded": ClassHash
238
  "ripple--unbounded": ClassHash
239
  "ripple--background-focused": ClassHash
240
  "ripple--foreground-activation": ClassHash
241
  "ripple--foreground-deactivation": ClassHash
242
  
243
  "ripple-upgraded": ClassHash
244
  "ripple-upgraded--bounded": ClassHash
245
  "ripple-upgraded--unbounded": ClassHash
246
  "ripple-upgraded--background-focused": ClassHash
247
  "ripple-upgraded--foreground-activation": ClassHash
248
  "ripple-upgraded--foreground-deactivation": ClassHash
249
    
250
  button: ClassHash
251
  "button--raised": ClassHash
252
  "button--type--raised": ClassHash
253
  "button--type--outlined": ClassHash
254
  button__label: ClassHash
255
  button__ripple: ClassHash
256
  button__icon: ClassHash
257
258
  dialog: ClassHash
259
  dialog__button: ClassHash
260
}
261