__tests__/readme.spec.tsx   A
last analyzed

Complexity

Total Complexity 6
Complexity/F 1.2

Size

Lines of Code 262
Function Count 5

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

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