generated from bloominstituteoftechnology/W_S5_Challenge
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mvp.test.js
243 lines (239 loc) · 11.2 KB
/
mvp.test.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
const { screen, fireEvent, within } = require('@testing-library/dom')
require('@testing-library/jest-dom')
const { version } = require('./package.json')
const { server } = require('./backend/mock')
const { learners, mentors } = require('./backend/data')
const { sprintChallenge5 } = require('./frontend/index')
const waitForOptions = { timeout: 150 } // so Codegrade does not take forever
beforeAll(() => { server.listen() })
afterAll(() => { server.close() })
beforeEach(async () => {
document.querySelector('body').innerHTML = `
<header>
<h1>Sprint 5 Challenge Submission</h1>
<h2>Learner Cards</h2>
<p class="info">Fetching learner cards...</p>
</header>
<section>
<div class="cards">
<!-- Learner cards are injected here by index.js script -->
</div>
</section>
<footer></footer>`
await sprintChallenge5()
})
async function firstCardRender() {
const bob = await screen.findByText('Bob Johnson', {}, waitForOptions)
expect(bob).toBeInTheDocument()
}
describe('Sprint Challenge 5', () => {
describe('Sprint setup', () => {
test('👉 [1] Version of challenge is valid', () => {
const versions = ['1.0.0']
expect(versions.indexOf(version)).toBeGreaterThan(-1)
})
test('👉 [2] The sprintChallenge5 function does not crash', async () => {
await expect(sprintChallenge5()).resolves.not.toThrowError()
})
test('👉 [3] The code inside the script is clean', () => {
expect(window.aidgfuioghausfdu).not.toBeDefined()
})
})
describe('Initial HTML', () => {
test('👉 [4] <h1> text is "Sprint 5 Challenge Submission"', () => {
screen.getByText('Sprint 5 Challenge Submission')
})
test('👉 [5] <h2> text is "Learner Cards"', () => {
screen.getByText('Learner Cards')
})
test('👉 [6] <footer> text is "© BLOOM INSTITUTE OF TECHNOLOGY 2023"', async () => {
screen.getByText('© BLOOM INSTITUTE OF TECHNOLOGY 2023')
})
})
describe('Successful Axios requests and DOM manipulation', () => {
test('👉 [7] <p class="info"> text is "No learner is selected" after rendering cards', async () => {
await firstCardRender()
screen.getByText('No learner is selected')
})
test('👉 [8] <div class="cards"> container holds 16 cards', async () => {
await firstCardRender()
expect(document.querySelector('.cards').children).toHaveLength(16)
})
test('👉 [9] <div class="card"> each card has a single class name "card"', async () => {
await firstCardRender()
expect(document.querySelectorAll('.card')).toHaveLength(16)
expect(document.querySelectorAll('.card.selected')).toHaveLength(0)
})
test('👉 [10] <h3> inside each card displays the proper name', async () => {
await firstCardRender()
const h3 = document.querySelectorAll('.card h3')
learners.forEach((l, idx) => {
l.fullName === h3[idx].textContent
})
})
test('👉 [11] <div> inside each card displays the proper email', async () => {
await firstCardRender()
const div = document.querySelectorAll('.card div')
learners.forEach((l, idx) => {
l.email === div[idx].textContent
})
})
test('👉 [12] <h4> inside each card displays the text "Mentors"', async () => {
await firstCardRender()
const h4 = document.querySelectorAll('.card h4')
h4.forEach(h => {
expect(h.textContent).toBe('Mentors')
})
})
test('👉 [13] <ul> inside each card displays the correct number of mentors', async () => {
await firstCardRender()
const unorderedLists = document.querySelectorAll('.card ul')
unorderedLists.forEach((ul, idx) => {
const lis = ul.querySelectorAll('li')
const ids = learners[idx].mentors
expect(lis.length).toBe(ids.length)
})
})
test('👉 [14] <li>s inside each card display the correct mentor names', async () => {
await firstCardRender()
const unorderedLists = document.querySelectorAll('.card ul')
unorderedLists.forEach((ul, idx) => {
const lis = ul.querySelectorAll('li')
const ids = learners[idx].mentors
const objs = ids.map(id => mentors.find(m => m.id == id))
const namesFromDOM = Array.from(lis).map(l => l.textContent)
const namesFromData = objs.map(o => `${o.firstName} ${o.lastName}`)
expect(namesFromDOM.sort()).toMatchObject(namesFromData.sort())
})
})
test('👉 [15] <ul> the mentors are hidden on page load', async () => {
await firstCardRender()
const cards = document.querySelectorAll('.card')
cards.forEach(c => {
const ul = c.querySelector('ul')
const h4 = c.querySelector('h4')
expect(ul).not.toBeVisible()
expect(h4.className).toBe('closed')
})
})
})
describe('Card Interactivity', () => {
test('👉 [16] <div class="card selected"> clicking on a card toggles a class of "selected" on it', async () => {
await firstCardRender()
const card = document.querySelector('.card:nth-child(1)')
expect(card.classList.contains('selected')).toBe(false)
fireEvent.click(card)
expect(card.classList.contains('selected')).toBe(true)
fireEvent.click(card)
expect(card.classList.contains('selected')).toBe(false)
})
test('👉 [17] <h3> selecting a card causes the learner ID to display next to the name', async () => {
await firstCardRender()
const card = document.querySelector('.card:nth-child(1)')
expect(within(card).queryByText('Bob Johnson, ID 6')).not.toBeInTheDocument()
fireEvent.click(card)
expect(within(card).queryByText('Bob Johnson, ID 6')).toBeInTheDocument()
fireEvent.click(card)
expect(within(card).queryByText('Bob Johnson, ID 6')).not.toBeInTheDocument()
})
test('👉 [18] <p class="info"> selecting a card displays the text "The selected learner is <name>"', async () => {
await firstCardRender()
const card1 = document.querySelector('.card:nth-child(1)')
const card2 = document.querySelector('.card:nth-child(2)')
const card3 = document.querySelector('.card:nth-child(3)')
fireEvent.click(card1)
expect(screen.queryByText('The selected learner is Bob Johnson')).toBeVisible()
fireEvent.click(card2)
expect(screen.queryByText('The selected learner is Bob Johnson')).not.toBeInTheDocument()
expect(screen.queryByText('The selected learner is Samantha Richards')).toBeVisible()
fireEvent.click(card3)
expect(screen.queryByText('The selected learner is Samantha Richards')).not.toBeInTheDocument()
expect(screen.queryByText('The selected learner is Harry Potter')).toBeVisible()
})
test('👉 [19] <p class="info"> de-selecting all cards displays the text "No learner is selected"', async () => {
await firstCardRender()
const card = document.querySelector('.card:nth-child(1)')
fireEvent.click(card)
fireEvent.click(card)
expect(screen.queryByText('No learner is selected')).toBeVisible()
})
test('👉 [20] <div class="card"> clicking on a card de-selects any other card that may be selected', async () => {
await firstCardRender()
const card1 = document.querySelector('.card:nth-child(1)')
const card2 = document.querySelector('.card:nth-child(2)')
const card3 = document.querySelector('.card:nth-child(3)')
fireEvent.click(card1)
fireEvent.click(card2)
expect(card1.classList.contains('selected')).toBe(false)
expect(card2.classList.contains('selected')).toBe(true)
expect(within(card1).queryByText('Bob Johnson, ID 6')).not.toBeInTheDocument()
expect(within(card2).queryByText('Samantha Richards, ID 52')).toBeInTheDocument()
fireEvent.click(card3)
expect(card2.classList.contains('selected')).toBe(false)
expect(card3.classList.contains('selected')).toBe(true)
expect(within(card2).queryByText('Samantha Richards, ID 52')).not.toBeInTheDocument()
expect(within(card3).queryByText('Harry Potter, ID 84')).toBeInTheDocument()
})
test('👉 [21] <h4 class="open"> clicking on "Mentors" heading toggles visibility of list of mentors', async () => {
// Repeatedly clicking on the h4 of a card causes the unordered list of mentors to switch
// from visible to invisible or vice-versa.
await firstCardRender()
const h4 = document.querySelector('.card:nth-child(4) h4')
fireEvent.click(h4)
expect(h4.classList.contains('closed')).toBe(false)
expect(h4.classList.contains('open')).toBe(true)
expect(h4.nextElementSibling).toBeVisible()
fireEvent.click(h4)
expect(h4.classList.contains('closed')).toBe(true)
expect(h4.classList.contains('open')).toBe(false)
expect(h4.nextElementSibling).not.toBeVisible()
})
test('👉 [22] <h4 class="open"> clicking on "Mentors" heading can select a card, but not deselect it', async () => {
// This means for example that, when clicking on the h4 of a de-selected card, it becomes selected and at the
// same time the visibility of the mentors list switches (from visible to invisible or vice-versa). However,
// when clicking again on the h4, the visibility of mentors switches, but the card does not become de-selected.
await firstCardRender()
const card = document.querySelector('.card:nth-child(8)')
const h4 = card.querySelector('h4')
fireEvent.click(h4)
expect(card.classList.contains('selected')).toBe(true)
fireEvent.click(h4)
expect(card.classList.contains('selected')).toBe(true)
})
test('👉 [23] <ul> the visibility of the mentors list is preserved on the old card, when selecting a new one', async () => {
// This means for example that, when selecting a new card by clicking on its h4, the visibility of the mentors
// list on the new card switches (from visible to invisible or vice-versa), but the visibility of the mentors
// list on the old card stays the way we left it
await firstCardRender()
const cardA = document.querySelector('.card:nth-child(8)')
const cardB = document.querySelector('.card:nth-child(2)')
const h4A = cardA.querySelector('h4')
const h4B = cardB.querySelector('h4')
const ulA = cardA.querySelector('ul')
const ulB = cardB.querySelector('ul')
fireEvent.click(h4A)
expect(cardA.classList.contains('selected')).toBe(true)
expect(ulA).toBeVisible()
fireEvent.click(h4B)
expect(cardA.classList.contains('selected')).not.toBe(true)
expect(cardB.classList.contains('selected')).toBe(true)
expect(ulA).toBeVisible()
expect(ulB).toBeVisible()
fireEvent.click(h4A)
expect(cardA.classList.contains('selected')).toBe(true)
expect(cardB.classList.contains('selected')).not.toBe(true)
expect(ulA).not.toBeVisible()
expect(ulB).toBeVisible()
fireEvent.click(h4B)
expect(cardA.classList.contains('selected')).not.toBe(true)
expect(cardB.classList.contains('selected')).toBe(true)
expect(ulA).not.toBeVisible()
expect(ulB).not.toBeVisible()
fireEvent.click(cardA)
expect(cardA.classList.contains('selected')).toBe(true)
expect(cardB.classList.contains('selected')).not.toBe(true)
expect(ulA).not.toBeVisible()
expect(ulB).not.toBeVisible()
})
})
})