@natachah/vanilla-frontend 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitlab-ci.yml +40 -0
- package/LICENSE.md +7 -0
- package/README.md +11 -0
- package/docs/index.html +36 -0
- package/docs/main.js +32 -0
- package/docs/pages/components/badge.html +154 -0
- package/docs/pages/components/button.html +186 -0
- package/docs/pages/components/card.html +184 -0
- package/docs/pages/components/dialog.html +334 -0
- package/docs/pages/components/disclosure.html +310 -0
- package/docs/pages/components/dropdown.html +255 -0
- package/docs/pages/components/form.html +331 -0
- package/docs/pages/components/list.html +140 -0
- package/docs/pages/components/loading.html +58 -0
- package/docs/pages/components/media.html +130 -0
- package/docs/pages/components/nav.html +119 -0
- package/docs/pages/components/progress.html +47 -0
- package/docs/pages/components/slider.html +311 -0
- package/docs/pages/components/table.html +168 -0
- package/docs/pages/javascript/autofill.html +170 -0
- package/docs/pages/javascript/checkall.html +59 -0
- package/docs/pages/javascript/comfort.html +134 -0
- package/docs/pages/javascript/consent.html +112 -0
- package/docs/pages/javascript/cookie.html +81 -0
- package/docs/pages/javascript/form.html +199 -0
- package/docs/pages/javascript/scroll.html +209 -0
- package/docs/pages/javascript/sidebar.html +53 -0
- package/docs/pages/javascript/sortable.html +148 -0
- package/docs/pages/javascript/toggle.html +191 -0
- package/docs/pages/javascript/tree.html +221 -0
- package/docs/pages/layout/grid.html +201 -0
- package/docs/pages/layout/reset.html +53 -0
- package/docs/pages/layout/typography.html +324 -0
- package/docs/pages/quick-start/conventions.html +112 -0
- package/docs/pages/quick-start/customization.html +187 -0
- package/docs/pages/quick-start/installation.html +95 -0
- package/docs/pages/quick-start/mixins.html +228 -0
- package/docs/pages/test.html +15 -0
- package/docs/src/js/demo.js +98 -0
- package/docs/src/js/doc-code.js +102 -0
- package/docs/src/js/doc-demo.js +14 -0
- package/docs/src/js/doc-layout.js +108 -0
- package/docs/src/scss/demo.scss +77 -0
- package/docs/src/scss/layout.scss +160 -0
- package/docs/src/scss/style.scss +278 -0
- package/docs/vite.config.mjs +23 -0
- package/esbuild.mjs +25 -0
- package/js/_autofill.js +131 -0
- package/js/_check-all.js +77 -0
- package/js/_comfort.js +174 -0
- package/js/_consent.js +84 -0
- package/js/_dialog.js +164 -0
- package/js/_dropdown.js +101 -0
- package/js/_scroll.js +184 -0
- package/js/_sidebar.js +97 -0
- package/js/_slider.js +249 -0
- package/js/_sortable.js +143 -0
- package/js/_tabpanel.js +88 -0
- package/js/_toggle.js +123 -0
- package/js/_tree.js +85 -0
- package/js/tests/autofill.test.js +157 -0
- package/js/tests/base-component.test.js +108 -0
- package/js/tests/check-all.test.js +88 -0
- package/js/tests/comfort.test.js +219 -0
- package/js/tests/consent.test.js +84 -0
- package/js/tests/cookie.test.js +102 -0
- package/js/tests/dialog.test.js +189 -0
- package/js/tests/dropdown.test.js +115 -0
- package/js/tests/form-helper.test.js +155 -0
- package/js/tests/scroll.test.js +203 -0
- package/js/tests/sidebar.test.js +99 -0
- package/js/tests/slider.test.js +307 -0
- package/js/tests/sortable.test.js +124 -0
- package/js/tests/tabpanel.test.js +114 -0
- package/js/tests/toggle.test.js +190 -0
- package/js/tests/tree.test.js +165 -0
- package/js/utilities/_base-component.js +101 -0
- package/js/utilities/_cookie.js +98 -0
- package/js/utilities/_error.js +80 -0
- package/js/utilities/_form-helper.js +101 -0
- package/package.json +42 -0
- package/scss/_badge.scss +37 -0
- package/scss/_button.scss +34 -0
- package/scss/_card.scss +122 -0
- package/scss/_dialog.scss +116 -0
- package/scss/_disclosure.scss +101 -0
- package/scss/_dropdown.scss +68 -0
- package/scss/_form.scss +197 -0
- package/scss/_grid.scss +40 -0
- package/scss/_group.scss +57 -0
- package/scss/_list.scss +18 -0
- package/scss/_loading.scss +49 -0
- package/scss/_media.scss +37 -0
- package/scss/_nav.scss +72 -0
- package/scss/_progress.scss +40 -0
- package/scss/_slider.scss +35 -0
- package/scss/_table.scss +36 -0
- package/scss/utilities/_mixin.scss +322 -0
- package/scss/utilities/_reset.scss +145 -0
- package/scss/utilities/_typography.scss +107 -0
- package/scss/vanilla-frontend.scss +23 -0
- package/scss/variables/_root.scss +70 -0
- package/scss/variables/_setting.scss +63 -0
- package/vitest.config.js +7 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ------------------------------------------------------------------
|
|
3
|
+
* TEST for the _sidebar.js
|
|
4
|
+
* ------------------------------------------------------------------
|
|
5
|
+
* The test will take care of:
|
|
6
|
+
* - Constructor: Passing the correct parameters
|
|
7
|
+
* - Constructor: Return the correct properties
|
|
8
|
+
* - #Init: On click on the button toggle the sidebar
|
|
9
|
+
* - #Init: On click on the backdrop, close the sidebar
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { describe, test, expect, beforeAll } from "vitest"
|
|
13
|
+
import { fireEvent } from "@testing-library/dom"
|
|
14
|
+
import Sidebar from "../_sidebar"
|
|
15
|
+
import ErrorMessage from "../utilities/_error"
|
|
16
|
+
|
|
17
|
+
let fakeSidebar
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Before all tests
|
|
21
|
+
*
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
beforeAll(() => {
|
|
25
|
+
|
|
26
|
+
document.body.innerHTML =
|
|
27
|
+
'<div id="backdrop"></div>' +
|
|
28
|
+
'<button aria-expanded="false" aria-pressed="false" aria-controls="sidebar"></button>' +
|
|
29
|
+
'<aside id="sidebar" tabindex="0" hidden></aside>'
|
|
30
|
+
|
|
31
|
+
Object.defineProperty(window, 'innerWidth', { configurable: true, value: 1200 })
|
|
32
|
+
|
|
33
|
+
fakeSidebar = new Sidebar(document.getElementById('sidebar'))
|
|
34
|
+
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
describe('Structure of the class', () => {
|
|
38
|
+
|
|
39
|
+
test('Constructor: Passing the correct parameters', () => {
|
|
40
|
+
expect(() => new Sidebar(document.getElementById('sidebar'), { breakpoint: 'make-error' })).toThrowError(ErrorMessage.typeOf('options.breakpoint', 'number'))
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('Constructor: Return the correct properties', () => {
|
|
44
|
+
expect(fakeSidebar._buttons).toStrictEqual(document.querySelectorAll('button[aria-controls="sidebar"]'))
|
|
45
|
+
expect(fakeSidebar._backdrop).toStrictEqual(document.getElementById('backdrop'))
|
|
46
|
+
expect(fakeSidebar._isOpen).toBeTruthy()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
describe('#Init(', () => {
|
|
52
|
+
|
|
53
|
+
test('On click on the button toggle the sidebar', () => {
|
|
54
|
+
|
|
55
|
+
const button = fakeSidebar._buttons[0]
|
|
56
|
+
|
|
57
|
+
expect(fakeSidebar._isOpen).toBeTruthy()
|
|
58
|
+
expect(fakeSidebar._element.hasAttribute('hidden')).toBeFalsy()
|
|
59
|
+
expect(button.getAttribute('aria-pressed')).toBe('true')
|
|
60
|
+
expect(button.getAttribute('aria-expanded')).toBe('true')
|
|
61
|
+
|
|
62
|
+
fireEvent(button, new MouseEvent('click'))
|
|
63
|
+
|
|
64
|
+
expect(fakeSidebar._isOpen).toBeFalsy()
|
|
65
|
+
expect(fakeSidebar._element.hasAttribute('hidden')).toBeTruthy()
|
|
66
|
+
expect(button.getAttribute('aria-pressed')).toBe('false')
|
|
67
|
+
expect(button.getAttribute('aria-expanded')).toBe('false')
|
|
68
|
+
|
|
69
|
+
fireEvent(button, new MouseEvent('click'))
|
|
70
|
+
|
|
71
|
+
expect(fakeSidebar._isOpen).toBeTruthy()
|
|
72
|
+
expect(fakeSidebar._element.hasAttribute('hidden')).toBeFalsy()
|
|
73
|
+
expect(button.getAttribute('aria-pressed')).toBe('true')
|
|
74
|
+
expect(button.getAttribute('aria-expanded')).toBe('true')
|
|
75
|
+
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test('On click on the backdrop, close the sidebar', () => {
|
|
79
|
+
|
|
80
|
+
Object.defineProperty(window, 'innerWidth', { configurable: true, value: 800 })
|
|
81
|
+
|
|
82
|
+
const button = fakeSidebar._buttons[0]
|
|
83
|
+
|
|
84
|
+
expect(fakeSidebar._isOpen).toBeTruthy()
|
|
85
|
+
expect(fakeSidebar._element.hasAttribute('hidden')).toBeFalsy()
|
|
86
|
+
expect(button.getAttribute('aria-pressed')).toBe('true')
|
|
87
|
+
expect(button.getAttribute('aria-expanded')).toBe('true')
|
|
88
|
+
|
|
89
|
+
fireEvent(document.getElementById('backdrop'), new MouseEvent('click'))
|
|
90
|
+
|
|
91
|
+
expect(fakeSidebar._isOpen).toBeFalsy()
|
|
92
|
+
expect(fakeSidebar._element.hasAttribute('hidden')).toBeTruthy()
|
|
93
|
+
expect(button.getAttribute('aria-pressed')).toBe('false')
|
|
94
|
+
expect(button.getAttribute('aria-expanded')).toBe('false')
|
|
95
|
+
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
})
|
|
99
|
+
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ------------------------------------------------------------------
|
|
3
|
+
* TEST for the /_slider.js
|
|
4
|
+
* ------------------------------------------------------------------
|
|
5
|
+
* The test will take care of:
|
|
6
|
+
* - Has all the public method
|
|
7
|
+
* ! herit from BaseComponent - Constructor: Passing the correct parameters
|
|
8
|
+
* - Constructor: Passing the correct parameters
|
|
9
|
+
* - Constructor: Return the correct properties
|
|
10
|
+
* - #Init(): Loop will clone the first and last slide
|
|
11
|
+
* - #Init(): Autoplay will emmit next() method every X ms
|
|
12
|
+
* - #Init(): Scroll will change the current attributes
|
|
13
|
+
* - #Init(): Click on <button> with [role=tab] emmit the goTo() method
|
|
14
|
+
* - #Init(): Click on <button> with [data-slider-prev] emmit the prev() method
|
|
15
|
+
* - #Init(): Click on <button> with [data-slider-next] emmit the next() method
|
|
16
|
+
* - GoTo(): Passing the correct parameters
|
|
17
|
+
* - GoTo(): Emit a scroll() method
|
|
18
|
+
* - Prev(): Emmit the goTo() method with correct index
|
|
19
|
+
* - Prev(): Don't emmit the goTo() method if already first slide
|
|
20
|
+
* - Next(): Emmit the goTo() method with correct index
|
|
21
|
+
* - Next(): Don't emmit the goTo() method if already last slide
|
|
22
|
+
* - #Change(): Change the [aria-selected], [aria-hidden] and [disabled] attributes
|
|
23
|
+
* - #Change(): Emmit the slider:changing and slider:changed events
|
|
24
|
+
* - #Loop(): Go to the last slide if too much left
|
|
25
|
+
* - #Loop(): Go to the first slide if too much right
|
|
26
|
+
* - #Loop(): Go to the first or last slide via toGo() method
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { describe, test, expect, beforeAll, vi, afterAll } from "vitest"
|
|
30
|
+
import { fireEvent } from "@testing-library/dom"
|
|
31
|
+
import Slider from "../_slider"
|
|
32
|
+
import ErrorMessage from "../utilities/_error"
|
|
33
|
+
|
|
34
|
+
let fakeDiv, fakeSlider, fakeDivLoop, fakeSliderLoop
|
|
35
|
+
|
|
36
|
+
function setScroll(value = 0, el = fakeDiv) {
|
|
37
|
+
Object.assign(el, { scrollLeft: value })
|
|
38
|
+
fireEvent.scroll(el, { target: { scrollX: value } })
|
|
39
|
+
vi.runAllTimers()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Before all tests
|
|
44
|
+
*
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
beforeAll(() => {
|
|
48
|
+
|
|
49
|
+
document.body.innerHTML =
|
|
50
|
+
'<div id="slider">' +
|
|
51
|
+
'<div id="1" role="tabpanel" aria-hidden="false"><img src="https://fakeimg.pl/760x506/?text=one"></div>' +
|
|
52
|
+
'<div id="2" role="tabpanel" aria-hidden="false"><img src="https://fakeimg.pl/760x506/?text=two"></div>' +
|
|
53
|
+
'<div id="3" role="tabpanel" aria-hidden="false"><img src="https://fakeimg.pl/760x506/?text=three"></div>' +
|
|
54
|
+
'</div>' +
|
|
55
|
+
'<div id="sliderLoop">' +
|
|
56
|
+
'<div id="4" role="tabpanel" aria-hidden="false"><img src="https://fakeimg.pl/760x506/?text=one"></div>' +
|
|
57
|
+
'<div id="5" role="tabpanel" aria-hidden="false"><img src="https://fakeimg.pl/760x506/?text=two"></div>' +
|
|
58
|
+
'<div id="6" role="tabpanel" aria-hidden="false"><img src="https://fakeimg.pl/760x506/?text=three"></div>' +
|
|
59
|
+
'</div>' +
|
|
60
|
+
'<div id="sliderAuto">' +
|
|
61
|
+
'<div id="7" role="tabpanel" aria-hidden="false"><img src="https://fakeimg.pl/760x506/?text=one"></div>' +
|
|
62
|
+
'<div id="8" role="tabpanel" aria-hidden="false"><img src="https://fakeimg.pl/760x506/?text=two"></div>' +
|
|
63
|
+
'</div>' +
|
|
64
|
+
'<div aria-controls="slider" role="tablist">' +
|
|
65
|
+
'<button role="tab" aria-controls="1" aria-selected="true">1</button>' +
|
|
66
|
+
'<button role="tab" aria-controls="2" aria-selected="false">2</button>' +
|
|
67
|
+
'<button role="tab" aria-controls="3" aria-selected="false">3</button>' +
|
|
68
|
+
'</div>' +
|
|
69
|
+
'<div>' +
|
|
70
|
+
'<button aria-controls="slider" data-slider-prev>previous</button>' +
|
|
71
|
+
'<button aria-controls="slider" data-slider-next>next</button>' +
|
|
72
|
+
'</div>'
|
|
73
|
+
|
|
74
|
+
fakeDiv = document.getElementById('slider')
|
|
75
|
+
Object.defineProperty(fakeDiv, 'scrollWidth', { configurable: true, value: 300 })
|
|
76
|
+
Object.defineProperty(fakeDiv, 'clientWidth', { configurable: true, value: 100 })
|
|
77
|
+
|
|
78
|
+
fakeDivLoop = document.getElementById('sliderLoop')
|
|
79
|
+
Object.defineProperty(fakeDivLoop, 'scrollWidth', { configurable: true, value: 300 })
|
|
80
|
+
Object.defineProperty(fakeDivLoop, 'offsetWidth', { configurable: true, value: 100 })
|
|
81
|
+
Object.defineProperty(fakeDivLoop, 'clientWidth', { configurable: true, value: 100 })
|
|
82
|
+
|
|
83
|
+
fakeSlider = new Slider(fakeDiv)
|
|
84
|
+
fakeSliderLoop = new Slider(fakeDivLoop, { loop: true })
|
|
85
|
+
|
|
86
|
+
Object.defineProperty(fakeSlider._slides[0], 'offsetLeft', { configurable: true, value: 0 })
|
|
87
|
+
Object.defineProperty(fakeSlider._slides[1], 'offsetLeft', { configurable: true, value: 100 })
|
|
88
|
+
Object.defineProperty(fakeSlider._slides[2], 'offsetLeft', { configurable: true, value: 200 })
|
|
89
|
+
|
|
90
|
+
let val = 0
|
|
91
|
+
fakeSliderLoop._element.children.forEach(child => {
|
|
92
|
+
Object.defineProperty(child, 'offsetLeft', { configurable: true, value: val })
|
|
93
|
+
val = val + 100
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
describe('Structure of the class', () => {
|
|
99
|
+
|
|
100
|
+
test('Has all the public method', () => {
|
|
101
|
+
expect(fakeSlider.goTo).toBeTypeOf('function')
|
|
102
|
+
expect(fakeSlider.prev).toBeTypeOf('function')
|
|
103
|
+
expect(fakeSlider.next).toBeTypeOf('function')
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test('Constructor: Passing the correct parameters', () => {
|
|
107
|
+
const htmlSlider = document.getElementById('slider')
|
|
108
|
+
expect(() => new Slider(htmlSlider, { behavior: 'make-error' })).toThrowError(ErrorMessage.enumOf('options.behavior', 'auto|smooth|instant'))
|
|
109
|
+
expect(() => new Slider(htmlSlider, { loop: 'make-error' })).toThrowError(ErrorMessage.typeOf('options.loop', 'boolean'))
|
|
110
|
+
expect(() => new Slider(htmlSlider, { autoplay: 'make-error' })).toThrowError(ErrorMessage.typeOf('options.autoplay', 'boolean|number'))
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
test('Constructor: Return the correct properties', () => {
|
|
114
|
+
expect(fakeSlider).toHaveProperty('_element')
|
|
115
|
+
expect(fakeSlider).toHaveProperty('_options')
|
|
116
|
+
expect(fakeSlider).toHaveProperty('_slides')
|
|
117
|
+
expect(fakeSlider).toHaveProperty('_buttons')
|
|
118
|
+
expect(fakeSlider).toHaveProperty('_current')
|
|
119
|
+
expect(fakeSlider).toHaveProperty('_interval')
|
|
120
|
+
expect(fakeSlider._slides).toBeTypeOf('object')
|
|
121
|
+
expect(fakeSlider._slides).toStrictEqual(document.querySelectorAll('#slider [role=tabpanel]'))
|
|
122
|
+
expect(fakeSlider._buttons).toBeTypeOf('object')
|
|
123
|
+
expect(fakeSlider._buttons.prev).toBeTypeOf('object')
|
|
124
|
+
expect(fakeSlider._buttons.next).toBeTypeOf('object')
|
|
125
|
+
expect(fakeSlider._buttons.tabs).toBeTypeOf('object')
|
|
126
|
+
expect(fakeSlider._buttons.prev).toStrictEqual(document.querySelector('[data-slider-prev]'))
|
|
127
|
+
expect(fakeSlider._buttons.next).toStrictEqual(document.querySelector('[data-slider-next]'))
|
|
128
|
+
expect(fakeSlider._buttons.tabs).toStrictEqual(document.querySelectorAll('[role=tablist] [role=tab]'))
|
|
129
|
+
expect(fakeSlider._current).toBe(0)
|
|
130
|
+
expect(fakeSlider._interval).toBeNull()
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
describe('#Init()', () => {
|
|
136
|
+
|
|
137
|
+
test('Loop will clone the first and last slide', () => {
|
|
138
|
+
expect(fakeSliderLoop._slides.length).toBe(3)
|
|
139
|
+
expect(fakeSliderLoop._element.children.length).toBe(5)
|
|
140
|
+
expect(fakeSliderLoop._element.firstElementChild.querySelector('img').getAttribute('src')).toContain('three')
|
|
141
|
+
expect(fakeSliderLoop._element.lastElementChild.querySelector('img').getAttribute('src')).toContain('one')
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
test('Autoplay will emmit next() method every X ms', () => {
|
|
145
|
+
vi.useFakeTimers()
|
|
146
|
+
const fakeSliderAuto = new Slider(document.getElementById('sliderAuto'), { autoplay: 1500 })
|
|
147
|
+
const methodSpy = vi.spyOn(fakeSliderAuto, 'next')
|
|
148
|
+
vi.advanceTimersByTime(3000)
|
|
149
|
+
expect(methodSpy).toHaveBeenCalledTimes(2)
|
|
150
|
+
clearInterval(fakeSliderAuto._interval)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
test('Scroll will change the current attributes', () => {
|
|
154
|
+
expect(fakeSlider._current).toBe(0)
|
|
155
|
+
setScroll(100)
|
|
156
|
+
expect(fakeSlider._current).toBe(1)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
test('Click on <button> with [role=tab] emmit the goTo() method', () => {
|
|
160
|
+
const fakeTab = fakeSlider._buttons.tabs[0]
|
|
161
|
+
const methodSpy = vi.spyOn(fakeSlider, 'goTo')
|
|
162
|
+
fireEvent(fakeTab, new MouseEvent('click'))
|
|
163
|
+
expect(methodSpy).toHaveBeenCalled()
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
test('Click on <button> with [data-slider-prev] emmit the prev() method', () => {
|
|
167
|
+
const fakePrev = fakeSlider._buttons.prev
|
|
168
|
+
const methodSpy = vi.spyOn(fakeSlider, 'prev')
|
|
169
|
+
fireEvent(fakePrev, new MouseEvent('click'))
|
|
170
|
+
expect(methodSpy).toHaveBeenCalled()
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
test('Click on <button> with [data-slider-next] emmit the next() method', () => {
|
|
174
|
+
const fakeNext = fakeSlider._buttons.next
|
|
175
|
+
const methodSpy = vi.spyOn(fakeSlider, 'next')
|
|
176
|
+
fireEvent(fakeNext, new MouseEvent('click'))
|
|
177
|
+
expect(methodSpy).toHaveBeenCalled()
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
describe('GoTo()', () => {
|
|
183
|
+
|
|
184
|
+
test('Passing the correct parameters', () => {
|
|
185
|
+
expect(() => fakeSlider.goTo()).toThrowError(ErrorMessage.typeOf('index', 'number'))
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
test('Emit a scroll() method', () => {
|
|
189
|
+
const scrollSpy = vi.spyOn(fakeDiv, 'scroll')
|
|
190
|
+
fakeSlider.goTo(0)
|
|
191
|
+
expect(scrollSpy).toHaveBeenCalledWith({
|
|
192
|
+
behavior: "smooth",
|
|
193
|
+
left: 0,
|
|
194
|
+
}, undefined)
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
describe('Prev()', () => {
|
|
200
|
+
|
|
201
|
+
afterAll(() => setScroll())
|
|
202
|
+
|
|
203
|
+
test('Emit a goTo() method with correct index', () => {
|
|
204
|
+
const methodSpy = vi.spyOn(fakeSlider, 'goTo')
|
|
205
|
+
fakeSlider.prev()
|
|
206
|
+
expect(methodSpy).toHaveBeenCalledWith(0)
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
test('Don\'t emmit the goTo() method if already first slide', () => {
|
|
210
|
+
const methodSpy = vi.spyOn(fakeSlider, 'goTo')
|
|
211
|
+
fakeSlider._current = 0
|
|
212
|
+
fakeSlider.prev()
|
|
213
|
+
expect(methodSpy).not.toHaveBeenCalled()
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
describe('Next()', () => {
|
|
219
|
+
|
|
220
|
+
afterAll(() => setScroll())
|
|
221
|
+
|
|
222
|
+
test('Emit a goTo() method and index is X', () => {
|
|
223
|
+
const methodSpy = vi.spyOn(fakeSlider, 'goTo')
|
|
224
|
+
fakeSlider.next()
|
|
225
|
+
expect(methodSpy).toHaveBeenCalledWith(1)
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
test('Don\'t emmit the goTo() method if already last slide', () => {
|
|
229
|
+
const methodSpy = vi.spyOn(fakeSlider, 'goTo')
|
|
230
|
+
fakeSlider._current = 2
|
|
231
|
+
fakeSlider.next()
|
|
232
|
+
expect(methodSpy).not.toHaveBeenCalled()
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
describe('#Change()', () => {
|
|
238
|
+
|
|
239
|
+
test('Toggle the [aria-selected], [aria-hidden] and [disabled] attributes', () => {
|
|
240
|
+
expect(fakeSlider._current).toBe(0)
|
|
241
|
+
expect(fakeSlider._slides[0].getAttribute('aria-hidden')).toBe('false')
|
|
242
|
+
expect(fakeSlider._buttons.tabs[0].getAttribute('aria-selected')).toBe('true')
|
|
243
|
+
expect(fakeSlider._buttons.prev.hasAttribute('disabled')).toBeTruthy()
|
|
244
|
+
setScroll(100)
|
|
245
|
+
expect(fakeSlider._current).toBe(1)
|
|
246
|
+
expect(fakeSlider._slides[0].getAttribute('aria-hidden')).toBe('true')
|
|
247
|
+
expect(fakeSlider._slides[1].getAttribute('aria-hidden')).toBe('false')
|
|
248
|
+
expect(fakeSlider._buttons.tabs[0].getAttribute('aria-selected')).toBe('false')
|
|
249
|
+
expect(fakeSlider._buttons.tabs[1].getAttribute('aria-selected')).toBe('true')
|
|
250
|
+
expect(fakeSlider._buttons.prev.hasAttribute('disabled')).toBeFalsy()
|
|
251
|
+
setScroll(200)
|
|
252
|
+
expect(fakeSlider._current).toBe(2)
|
|
253
|
+
expect(fakeSlider._slides[1].getAttribute('aria-hidden')).toBe('true')
|
|
254
|
+
expect(fakeSlider._slides[2].getAttribute('aria-hidden')).toBe('false')
|
|
255
|
+
expect(fakeSlider._buttons.tabs[1].getAttribute('aria-selected')).toBe('false')
|
|
256
|
+
expect(fakeSlider._buttons.tabs[2].getAttribute('aria-selected')).toBe('true')
|
|
257
|
+
expect(fakeSlider._buttons.next.hasAttribute('disabled')).toBeTruthy()
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
test('Emmit the slider:changing and slider:changed events', () => {
|
|
261
|
+
const eventSpy = vi.spyOn(fakeSlider, 'emmitEvent')
|
|
262
|
+
setScroll(0)
|
|
263
|
+
expect(eventSpy).toHaveBeenCalledWith('changing', { current: 2 })
|
|
264
|
+
expect(eventSpy).toHaveBeenCalledWith('changed', { current: 0 })
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
describe('#Loop()', () => {
|
|
270
|
+
|
|
271
|
+
test('Go to the last slide if too much left', () => {
|
|
272
|
+
const scrollSpy = vi.spyOn(fakeDivLoop, 'scroll')
|
|
273
|
+
expect(fakeSliderLoop._current).toBe(0)
|
|
274
|
+
setScroll(0, fakeDivLoop)
|
|
275
|
+
expect(fakeSliderLoop._current).toBe(2)
|
|
276
|
+
expect(scrollSpy).toHaveBeenCalledWith(300, 0)
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
test('Go to the first slide if too much right', () => {
|
|
280
|
+
const scrollSpy = vi.spyOn(fakeDivLoop, 'scroll')
|
|
281
|
+
expect(fakeSliderLoop._current).toBe(2)
|
|
282
|
+
setScroll(400, fakeDivLoop)
|
|
283
|
+
expect(fakeSliderLoop._current).toBe(0)
|
|
284
|
+
expect(scrollSpy).toHaveBeenCalledWith(100, 0)
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
test('Go to the first or last slide via toGo() method', () => {
|
|
288
|
+
|
|
289
|
+
const scrollSpy = vi.spyOn(fakeDivLoop, 'scroll')
|
|
290
|
+
|
|
291
|
+
fakeSliderLoop.goTo(-1)
|
|
292
|
+
|
|
293
|
+
expect(scrollSpy).toHaveBeenCalledWith({
|
|
294
|
+
behavior: "smooth",
|
|
295
|
+
left: 0,
|
|
296
|
+
}, undefined)
|
|
297
|
+
|
|
298
|
+
fakeSliderLoop.goTo(3)
|
|
299
|
+
|
|
300
|
+
expect(scrollSpy).toHaveBeenCalledWith({
|
|
301
|
+
behavior: "smooth",
|
|
302
|
+
left: 400,
|
|
303
|
+
}, undefined)
|
|
304
|
+
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
})
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ------------------------------------------------------------------
|
|
3
|
+
* TEST for the _sortable.js
|
|
4
|
+
* ------------------------------------------------------------------
|
|
5
|
+
* The test will take care of:
|
|
6
|
+
* ! NONE ! - Has all the public method
|
|
7
|
+
* ! Tested in BaseComponent ! - Constructor: Passing the correct parameters
|
|
8
|
+
* - Constructor: Return the correct properties
|
|
9
|
+
* - Mousedown & Mouseup: Without handle toggle the [draggable] attribute
|
|
10
|
+
* - Mousedown & Mouseup: With handle toggle the [draggable] attribute
|
|
11
|
+
* - #Drag(): Add the [aria-grabbed] attribute
|
|
12
|
+
* - #Drag(): Emmit the sortable:drag event
|
|
13
|
+
* - #Drop(): Remove the [aria-grabbed] attribute
|
|
14
|
+
* - #Drop(): Emmit the sortable:drop event
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { describe, test, expect, beforeAll, vi } from "vitest"
|
|
18
|
+
import { fireEvent } from "@testing-library/dom"
|
|
19
|
+
import Sortable from "../_sortable"
|
|
20
|
+
|
|
21
|
+
let fakeListSortable, fakeTableSortable, fakeListItem
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Before all tests
|
|
25
|
+
*
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
beforeAll(() => {
|
|
29
|
+
|
|
30
|
+
document.body.innerHTML =
|
|
31
|
+
'<ul id="fakeList">' +
|
|
32
|
+
'<li draggable="false">One</li>' +
|
|
33
|
+
'<li draggable="false">Two</li>' +
|
|
34
|
+
'<li draggable="false">Three</li>' +
|
|
35
|
+
'</ul>' +
|
|
36
|
+
'<table id="fakeTable">' +
|
|
37
|
+
'<tr draggable="false"><td data-handle>DRAG</td><td>One</td></tr>' +
|
|
38
|
+
'<tr draggable="false"><td data-handle>DRAG</td><td>Two</td></tr>' +
|
|
39
|
+
'<tr draggable="false"><td data-handle>DRAG</td><td>Three</td></tr>' +
|
|
40
|
+
'</table>'
|
|
41
|
+
|
|
42
|
+
fakeListSortable = new Sortable(document.getElementById('fakeList'))
|
|
43
|
+
fakeTableSortable = new Sortable(document.getElementById('fakeTable'))
|
|
44
|
+
fakeListItem = document.querySelector('#fakeList li')
|
|
45
|
+
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
describe('Structure of the class', () => {
|
|
49
|
+
|
|
50
|
+
test('Constructor: Return the correct properties', () => {
|
|
51
|
+
expect(fakeListSortable).toHaveProperty('_withHandle')
|
|
52
|
+
expect(fakeListSortable._withHandle).toBeTypeOf('boolean')
|
|
53
|
+
expect(fakeListSortable._withHandle).toBe(false)
|
|
54
|
+
expect(fakeTableSortable._withHandle).toBe(true)
|
|
55
|
+
expect(fakeListSortable.items).toBeTypeOf('object')
|
|
56
|
+
expect(fakeListSortable.items).toStrictEqual(document.querySelectorAll('#fakeList li'))
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
describe('Mousedown & Mouseup', () => {
|
|
62
|
+
|
|
63
|
+
test('Without handle toggle the [draggable] attribute', () => {
|
|
64
|
+
expect(fakeListItem.draggable).toBeFalsy()
|
|
65
|
+
fireEvent(fakeListItem, new MouseEvent('mousedown'))
|
|
66
|
+
expect(fakeListItem.draggable).toBeTruthy()
|
|
67
|
+
fireEvent(fakeListItem, new MouseEvent('mouseup'))
|
|
68
|
+
expect(fakeListItem.draggable).toBeFalsy()
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('With handle & Mouseup toggle the [draggable] attribute', () => {
|
|
72
|
+
const item = document.querySelector('#fakeTable tr')
|
|
73
|
+
const handle = document.querySelector('#fakeTable tr:first-child [data-handle]')
|
|
74
|
+
const customMousedown = new MouseEvent('mousedown')
|
|
75
|
+
Object.defineProperty(customMousedown, 'target', { value: handle }) // Define the mousedown event with custom target
|
|
76
|
+
expect(item.draggable).toBeFalsy()
|
|
77
|
+
fireEvent(item, new MouseEvent('mousedown'))
|
|
78
|
+
expect(item.draggable).toBeFalsy()
|
|
79
|
+
fireEvent(item, customMousedown)
|
|
80
|
+
expect(item.draggable).toBeTruthy()
|
|
81
|
+
fireEvent(item, new MouseEvent('mouseup'))
|
|
82
|
+
expect(item.draggable).toBeFalsy()
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
describe('#Drag()', () => {
|
|
88
|
+
|
|
89
|
+
test('Add the [aria-grabbed] attribute', () => {
|
|
90
|
+
expect(fakeListItem.hasAttribute('aria-grabbed')).toBeFalsy()
|
|
91
|
+
fireEvent(fakeListItem, new MouseEvent('mousedown'))
|
|
92
|
+
fireEvent(fakeListItem, new MouseEvent('dragstart'))
|
|
93
|
+
expect(fakeListItem.hasAttribute('aria-grabbed')).toBeTruthy()
|
|
94
|
+
fireEvent(fakeListItem, new MouseEvent('dragend'))
|
|
95
|
+
fireEvent(fakeListItem, new MouseEvent('mouseup'))
|
|
96
|
+
expect(fakeListItem.hasAttribute('aria-grabbed')).toBeFalsy()
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
test('Emmit the sortable:drag event', () => {
|
|
100
|
+
const eventSpy = vi.spyOn(fakeListSortable, 'emmitEvent')
|
|
101
|
+
expect(eventSpy).not.toHaveBeenCalled()
|
|
102
|
+
fireEvent(fakeListItem, new MouseEvent('mousedown'))
|
|
103
|
+
fireEvent(fakeListItem, new MouseEvent('dragstart'))
|
|
104
|
+
expect(eventSpy).toHaveBeenCalledWith('drag', { current: fakeListItem, items: fakeListSortable.items })
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
describe('#Drop()', () => {
|
|
110
|
+
|
|
111
|
+
test('Remove the [aria-grabbed] attribute', () => {
|
|
112
|
+
expect(fakeListItem.hasAttribute('aria-grabbed')).toBeTruthy()
|
|
113
|
+
fireEvent(fakeListItem, new MouseEvent('dragend'))
|
|
114
|
+
expect(fakeListItem.hasAttribute('aria-grabbed')).toBeFalsy()
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
test('Emmit the sortable:drop event', () => {
|
|
118
|
+
const eventSpy = vi.spyOn(fakeListSortable, 'emmitEvent')
|
|
119
|
+
expect(eventSpy).not.toHaveBeenCalled()
|
|
120
|
+
fireEvent(fakeListItem, new MouseEvent('dragend'))
|
|
121
|
+
expect(eventSpy).toHaveBeenCalledWith('drop', { current: fakeListItem, items: fakeListSortable.items })
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
})
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ------------------------------------------------------------------
|
|
3
|
+
* TEST for the_tabpabel.js
|
|
4
|
+
* ------------------------------------------------------------------
|
|
5
|
+
* The test will take care of:
|
|
6
|
+
* ! herit from BaseComponent - Constructor: Passing the correct parameters
|
|
7
|
+
* - Constructor: Passing the correct parameters
|
|
8
|
+
* - Constructor: Return the correct properties
|
|
9
|
+
* - #Change(): Toggle the [aria-selected] attribute on the tab
|
|
10
|
+
* - #Change(): Toggle the [hidden] attribute on the panel
|
|
11
|
+
* - #Change(): Emmit the tabpanel:changed event
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { describe, test, expect, beforeAll, vi } from "vitest"
|
|
15
|
+
import { fireEvent } from "@testing-library/dom"
|
|
16
|
+
import Tabpanel from "../_tabpanel"
|
|
17
|
+
import ErrorMessage from "../utilities/_error"
|
|
18
|
+
|
|
19
|
+
let fakeTabpanel, fakeTabA, fakeTabB, fakeTabC, fakePanelA, fakePanelB
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Before all tests
|
|
23
|
+
*
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
beforeAll(() => {
|
|
27
|
+
|
|
28
|
+
document.body.innerHTML =
|
|
29
|
+
'<div id="tabpanel">' +
|
|
30
|
+
'<div role="tablist">' +
|
|
31
|
+
'<button role="tab" aria-controls="a" aria-selected="false">A</button>' +
|
|
32
|
+
'<button role="tab" aria-controls="b" aria-selected="false">B</button>' +
|
|
33
|
+
'<button role="tab" aria-selected="false">C</button>' +
|
|
34
|
+
'</div>' +
|
|
35
|
+
'<div role="tabpanel" id="a" hidden>AAA</div>' +
|
|
36
|
+
'<div role="tabpanel" id="b" hidden>BBB</div>' +
|
|
37
|
+
'<div role="tabpanel" id="c" hidden>CCC</div>' +
|
|
38
|
+
'</div>'
|
|
39
|
+
|
|
40
|
+
fakeTabpanel = new Tabpanel(document.getElementById('tabpanel'))
|
|
41
|
+
fakeTabA = fakeTabpanel._tabs[0]
|
|
42
|
+
fakeTabB = fakeTabpanel._tabs[1]
|
|
43
|
+
fakeTabC = fakeTabpanel._tabs[2]
|
|
44
|
+
fakePanelA = fakeTabpanel._panels[0]
|
|
45
|
+
fakePanelB = fakeTabpanel._panels[1]
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
describe('Structure of the class', () => {
|
|
49
|
+
|
|
50
|
+
test('Constructor: Passing the correct parameters', () => {
|
|
51
|
+
const fakeWrong = document.createElement('div')
|
|
52
|
+
expect(() => new Tabpanel(fakeWrong)).toThrowError(ErrorMessage.exist('button [role="tab"]'))
|
|
53
|
+
const fakeTab = document.createElement('button')
|
|
54
|
+
fakeTab.setAttribute('role', 'tab')
|
|
55
|
+
fakeWrong.appendChild(fakeTab)
|
|
56
|
+
expect(() => new Tabpanel(fakeWrong)).toThrowError(ErrorMessage.exist('div [role="tabpanel"]'))
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('Constructor: Return the correct properties', () => {
|
|
60
|
+
expect(fakeTabpanel).toHaveProperty('_tabs')
|
|
61
|
+
expect(fakeTabpanel).toHaveProperty('_panels')
|
|
62
|
+
expect(fakeTabpanel).toHaveProperty('_current')
|
|
63
|
+
expect(fakeTabpanel._tabs).toBeTypeOf('object')
|
|
64
|
+
expect(fakeTabpanel._panels).toBeTypeOf('object')
|
|
65
|
+
expect(fakeTabpanel._current).toBeTypeOf('object')
|
|
66
|
+
expect(fakeTabpanel._tabs).toStrictEqual(document.querySelectorAll('#tabpanel [role="tab"]'))
|
|
67
|
+
expect(fakeTabpanel._panels).toStrictEqual(document.querySelectorAll('#tabpanel [role="tabpanel"]'))
|
|
68
|
+
expect(fakeTabpanel._current).toStrictEqual(document.querySelector('#tabpanel button'))
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
describe('#Change()', () => {
|
|
74
|
+
|
|
75
|
+
test('Toggle the [aria-selected] attribute on the tab', () => {
|
|
76
|
+
expect(fakeTabA.getAttribute('aria-selected')).toBe('true')
|
|
77
|
+
expect(fakeTabB.getAttribute('aria-selected')).toBe('false')
|
|
78
|
+
fireEvent(fakeTabB, new MouseEvent('click'))
|
|
79
|
+
expect(fakeTabA.getAttribute('aria-selected')).toBe('false')
|
|
80
|
+
expect(fakeTabB.getAttribute('aria-selected')).toBe('true')
|
|
81
|
+
fireEvent(fakeTabC, new MouseEvent('click'))
|
|
82
|
+
expect(fakeTabA.getAttribute('aria-selected')).toBe('false')
|
|
83
|
+
expect(fakeTabB.getAttribute('aria-selected')).toBe('true')
|
|
84
|
+
fireEvent(fakeTabA, new MouseEvent('click'))
|
|
85
|
+
expect(fakeTabA.getAttribute('aria-selected')).toBe('true')
|
|
86
|
+
expect(fakeTabB.getAttribute('aria-selected')).toBe('false')
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
test('Toggle the [hidden] attribute on the panel', () => {
|
|
90
|
+
expect(fakePanelA.hidden).toBeFalsy()
|
|
91
|
+
expect(fakePanelB.hidden).toBeTruthy()
|
|
92
|
+
fireEvent(fakeTabB, new MouseEvent('click'))
|
|
93
|
+
expect(fakePanelA.hidden).toBeTruthy()
|
|
94
|
+
expect(fakePanelB.hidden).toBeFalsy()
|
|
95
|
+
fireEvent(fakeTabC, new MouseEvent('click'))
|
|
96
|
+
expect(fakePanelA.hidden).toBeTruthy()
|
|
97
|
+
expect(fakePanelB.hidden).toBeFalsy()
|
|
98
|
+
fireEvent(fakeTabA, new MouseEvent('click'))
|
|
99
|
+
expect(fakePanelA.hidden).toBeFalsy()
|
|
100
|
+
expect(fakePanelB.hidden).toBeTruthy()
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test('Emmit the tabpanel:changed event', () => {
|
|
104
|
+
const eventSpy = vi.spyOn(fakeTabpanel, 'emmitEvent')
|
|
105
|
+
expect(eventSpy).not.toHaveBeenCalled()
|
|
106
|
+
fireEvent(fakeTabA, new MouseEvent('click'))
|
|
107
|
+
expect(eventSpy).not.toHaveBeenCalled()
|
|
108
|
+
fireEvent(fakeTabC, new MouseEvent('click'))
|
|
109
|
+
expect(eventSpy).not.toHaveBeenCalled()
|
|
110
|
+
fireEvent(fakeTabB, new MouseEvent('click'))
|
|
111
|
+
expect(eventSpy).toHaveBeenCalledWith('changed', { current: fakeTabB })
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
})
|