-
-
Notifications
You must be signed in to change notification settings - Fork 237
Expand file tree
/
Copy pathspec.js
More file actions
167 lines (155 loc) · 4.91 KB
/
spec.js
File metadata and controls
167 lines (155 loc) · 4.91 KB
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
const lolex = require('lolex')
const trim = text => text.trim()
const toDoubleQuots = text => text.replace(/'/g, '"')
const isMultiLine = text => text.includes('\n')
const isCommentLine = text => text.trim().startsWith('//')
const isNonCommentLine = text => !isCommentLine(text)
const convertSingleTextLine = text => {
const quoted = toDoubleQuots(text)
try {
return JSON.parse(quoted)
} catch (err) {
console.error('could not parse text')
console.error(quoted)
return
}
}
const removeComments = text =>
text
.split('\n')
.filter(isNonCommentLine)
.join('\n')
// we need to get JavaScript data from the code text
// there might be single quotes, comments - we need to clean this up
// also each output line means there was different console.log call
const parseText = text =>
text
.split('\n')
.filter(isNonCommentLine)
.map(convertSingleTextLine)
describe('array-explorer', () => {
let fakeClock
beforeEach(() => {
cy.visit('http://localhost:8080', {
onBeforeLoad: win => {
fakeClock = lolex.install({
target: win,
})
},
})
})
// utility functions
const selectMethod = choice => cy.get('#firstmethod').select(choice)
const selectMethodOptions = choice => cy.get('#methodoptions').select(choice)
const confirmInputAndOutput = () => {
cy
.get('.exampleoutput2')
.as('output')
.invoke('text')
.then(removeComments)
.as('outputText')
.then(parseText)
.as('outputValues')
.then(() => {
fakeClock.tick(10000)
})
// set up spy on `console.log` before
// we can call `eval(input code)`
cy.spy(console, 'log')
cy
.get('.usage1')
.invoke('text')
.then(sourceCode => {
// show message in the command log
cy.log('evaluating', sourceCode)
// there is one test that has hardcoded output date
// mock clock and pass fake "Date" object into `eval`
// to get the same date when called
var clock = Cypress.sinon.useFakeTimers(
new Date('12/26/2017, 6:54:49 PM').getTime()
)
{
// evaluate the input code - we are already spying on console.log!
eval('const Date = clock.Date;' + sourceCode)
}
// don't forget to restore system clock
// otherwise good things will not happen
clock.restore()
eval(sourceCode)
})
// confirm console.log with expected values happened in order
cy.get('@outputValues').then(outputValues => {
outputValues.forEach((value, k) => {
expect(console.log.getCall(k)).to.have.been.calledWith(value)
})
})
// make sure the output text actually appears
cy.get('@outputText').then(outputText => {
cy.get('@output').should('have.css', 'opacity', '1')
// the only difficulty is with multiline text where there might
// be white space at the start of each line
outputText
.split('\n')
.map(trim)
.forEach(line => {
cy.get('@output').should('contain', line)
})
})
}
it('loads', () => {
cy.contains('h1', 'JavaScript Array Explorer')
})
it('works in Russian', () => {
cy.get('[data-attr-cy="language"').select('Russian')
selectMethod('удалить элементы') // remove elements
selectMethodOptions('первый элемент массива') // first element of the array
confirmInputAndOutput()
})
const methods = {
'add items or other arrays': [
'element/s to an array',
'elements to the end of an array',
'elements to the front of an array',
'this array to other array(s) and/or value(s)',
],
'remove items': [
'element/s from an array',
'the last element of the array',
'the first element of the array',
'one or more elements in order for use, leaving the array as is',
],
// skip "find items" - requires multiple parameters
'walk over items': [
'executing a function I will create for each element',
'creating a new array from each element with a function I create',
'creating an iterator object',
],
'return a string': [
'join all elements of the array into a string',
'return a string representing the array.',
'return a localized string representing the array.',
],
'order an array': [
'reverse the order of the array',
'sort the items of the array',
],
'something else': [
'find the length of the array',
'fill all the elements of the array with a static value',
'copy a sequence of array elements within the array.',
],
}
Object.keys(methods).forEach(method => {
context(method, () => {
beforeEach(() => {
selectMethod(method)
})
methods[method].forEach(secondary => {
it(secondary, () => {
selectMethodOptions(secondary)
confirmInputAndOutput()
})
})
})
})
})