Skip to content

Commit c3783fb

Browse files
authored
feat(6282): add SQL composition e2es (#6501)
* chore: correct wording in test * feat(6282): add sql composition tests * chore(6282): move writeData fixture into before() all tests
1 parent 97091d2 commit c3783fb

File tree

2 files changed

+337
-1
lines changed

2 files changed

+337
-1
lines changed

cypress/e2e/shared/scriptQueryBuilder.flux.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ describe('Script Builder', () => {
495495
clearSession()
496496
})
497497

498-
it('should not be able to modify the composition when unsynced, yet still modify the saved schema -- which updates the composition when re-synced', () => {
498+
it('should not be able to modify the composition when unsynced, yet still modify the session -- which updates the composition when re-synced', () => {
499499
cy.log('empty editor text')
500500
cy.getByTestID('flux-editor').monacoType('{selectall}{enter}')
501501

Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
import {Organization} from '../../../src/types'
2+
3+
const DEFAULT_SQL_EDITOR_TEXT = '/* Start by typing SQL here */'
4+
5+
const DELAY_FOR_LAZY_LOAD_EDITOR = 30000
6+
7+
describe('Script Builder', () => {
8+
const bucketName = 'defbuck'
9+
const measurement = 'ndbc'
10+
11+
const selectBucket = (bucketName: string) => {
12+
cy.getByTestID('bucket-selector--dropdown-button').click()
13+
cy.getByTestID(`bucket-selector--dropdown--${bucketName}`).click()
14+
cy.getByTestID('bucket-selector--dropdown-button').should(
15+
'contain',
16+
bucketName
17+
)
18+
}
19+
20+
const selectMeasurement = (measurement: string) => {
21+
cy.getByTestID('measurement-selector--dropdown-button')
22+
.should('be.visible')
23+
.should('contain', 'Select measurement')
24+
.click()
25+
cy.getByTestID('measurement-selector--dropdown--menu').type(measurement)
26+
cy.getByTestID(`searchable-dropdown--item ${measurement}`)
27+
.should('be.visible')
28+
.click()
29+
cy.getByTestID('measurement-selector--dropdown-button').should(
30+
'contain',
31+
measurement
32+
)
33+
}
34+
35+
const selectListItem = (name, beActive) => {
36+
cy.getByTestID('field-selector').should('be.visible')
37+
cy.getByTestID(`selector-list ${name}`)
38+
.should('be.visible')
39+
.click({force: true})
40+
cy.getByTestID(`selector-list ${name}`).should(
41+
beActive ? 'have.class' : 'not.have.class',
42+
'cf-list-item__active'
43+
)
44+
}
45+
46+
const confirmSyncIsOn = () => {
47+
return cy.getByTestID('editor-sync--toggle').then($toggle => {
48+
if (!$toggle.hasClass('active')) {
49+
$toggle.click()
50+
}
51+
})
52+
}
53+
54+
const selectSchema = () => {
55+
cy.log('select bucket')
56+
selectBucket(bucketName)
57+
confirmSyncIsOn() // SQL composition is dumb. On bucket selection, it will occasionally drop the sync.
58+
cy.log('writes empty query statement with only the timerange')
59+
cy.getByTestID('sql-editor', {
60+
timeout: DELAY_FOR_LAZY_LOAD_EDITOR,
61+
}).contains(`SELECT *`)
62+
cy.getByTestID('sql-editor').contains(`WHERE`)
63+
cy.getByTestID('sql-editor').contains(`time >= now() - interval '1 hour'`)
64+
65+
cy.log('select measurement')
66+
selectMeasurement(measurement)
67+
}
68+
69+
const confirmSchemaComposition = () => {
70+
cy.log('has basic query')
71+
cy.getByTestID('sql-editor', {
72+
timeout: DELAY_FOR_LAZY_LOAD_EDITOR,
73+
}).contains(`SELECT *`)
74+
cy.getByTestID('sql-editor').contains(`WHERE`)
75+
cy.getByTestID('sql-editor').contains(`time >= now() - interval '1 hour'`)
76+
77+
cy.log('has measurement chosen as a table')
78+
cy.getByTestID('sql-editor').contains(`FROM "${measurement}"`)
79+
cy.getByTestID('sql-editor').within(() => {
80+
cy.get('.composition-sync--on').should('have.length', 4)
81+
})
82+
83+
cy.log('does not have other fields or tag filters')
84+
cy.getByTestID('sql-editor').should('not.contain', 'AND')
85+
}
86+
87+
const setScriptToSql = () => {
88+
return cy.isIoxOrg().then(isIox => {
89+
if (isIox) {
90+
cy.getByTestID('query-builder--new-script').should('be.visible').click()
91+
cy.getByTestID('script-dropdown__sql').should('be.visible').click()
92+
cy.getByTestID('overlay--container').within(() => {
93+
cy.getByTestID('script-query-builder--no-save')
94+
.should('be.visible')
95+
.click()
96+
})
97+
}
98+
return cy.getByTestID('sql-editor').within(() => {
99+
cy.get('textarea.inputarea').should(
100+
'have.value',
101+
DEFAULT_SQL_EDITOR_TEXT
102+
)
103+
})
104+
})
105+
}
106+
107+
const clearSession = () => {
108+
return cy.isIoxOrg().then(isIox => {
109+
if (isIox) {
110+
setScriptToSql()
111+
} else {
112+
cy.skipOn(true)
113+
}
114+
cy.getByTestID('sql-editor').within(() => {
115+
cy.get('textarea.inputarea').should(
116+
'have.value',
117+
DEFAULT_SQL_EDITOR_TEXT
118+
)
119+
})
120+
return confirmSyncIsOn()
121+
})
122+
}
123+
124+
const loginWithFlags = flags => {
125+
return cy.signinWithoutUserReprovision().then(() => {
126+
return cy.get('@org').then(({id}: Organization) => {
127+
cy.visit(`/orgs/${id}/data-explorer`)
128+
return cy.setFeatureFlags(flags).then(() => {
129+
cy.getByTestID('script-query-builder-toggle').then($toggle => {
130+
cy.wrap($toggle).should('be.visible')
131+
// Switch to Script Query Builder if not yet
132+
if (!$toggle.hasClass('active')) {
133+
// hasClass is a jQuery function
134+
$toggle.click()
135+
}
136+
})
137+
})
138+
})
139+
})
140+
}
141+
142+
before(() => {
143+
const writeData: string[] = []
144+
for (let i = 0; i < 30; i++) {
145+
writeData.push(`ndbc,air_temp_degc=70_degrees station_id_${i}=${i}`)
146+
writeData.push(`ndbc2,air_temp_degc=70_degrees station_id_${i}=${i}`)
147+
}
148+
149+
cy.flush().then(() => {
150+
return cy.signin().then(() => {
151+
return cy.get('@org').then(({id, name}: Organization) => {
152+
cy.log('add mock data')
153+
cy.createBucket(id, name, 'defbuck2')
154+
cy.writeData(writeData, 'defbuck')
155+
cy.writeData(writeData, 'defbuck2')
156+
})
157+
})
158+
})
159+
})
160+
161+
describe('Schema Composition', () => {
162+
beforeEach(() => {
163+
loginWithFlags({
164+
schemaComposition: true,
165+
newDataExplorer: true,
166+
saveAsScript: true,
167+
}).then(() => {
168+
clearSession()
169+
cy.getByTestID('editor-sync--toggle')
170+
cy.getByTestID('sql-editor', {timeout: DELAY_FOR_LAZY_LOAD_EDITOR})
171+
})
172+
})
173+
174+
describe('basic functionality', () => {
175+
it('can construct a composition with fields', () => {
176+
cy.log('empty editor text')
177+
cy.getByTestID('sql-editor').monacoType('{selectAll}{del}')
178+
179+
cy.log('select bucket and measurement')
180+
selectSchema()
181+
confirmSyncIsOn() // SQL composition is dumb. On bucket selection, it will occasionally drop the sync.
182+
confirmSchemaComposition()
183+
184+
cy.log('select field --> adds to composition')
185+
const fieldName0 = 'station_id_0'
186+
const fieldName10 = 'station_id_10'
187+
selectListItem(fieldName0, true)
188+
cy.getByTestID('sql-editor').contains(`("${fieldName0}" IS NOT NULL)`)
189+
selectListItem(fieldName10, true)
190+
cy.getByTestID('sql-editor').contains(
191+
`("${fieldName0}" IS NOT NULL OR "${fieldName10}" IS NOT NULL)`
192+
)
193+
194+
cy.log('select field --> removes from composition')
195+
selectListItem(fieldName10, false)
196+
cy.wait(1000)
197+
cy.getByTestID('sql-editor').contains(`("${fieldName0}" IS NOT NULL)`)
198+
cy.getByTestID('sql-editor').within(() => {
199+
cy.get('textarea.inputarea').should('not.contain', fieldName10)
200+
})
201+
})
202+
203+
it('can construct a composition with tagValues', () => {
204+
cy.log('empty editor text')
205+
cy.getByTestID('sql-editor').monacoType('{selectAll}{del}')
206+
207+
cy.log('select bucket and measurement')
208+
selectSchema()
209+
confirmSyncIsOn() // SQL composition is dumb. On bucket selection, it will occasionally drop the sync.
210+
confirmSchemaComposition()
211+
212+
cy.log('select tagValue --> adds to composition')
213+
cy.getByTestID('container-side-bar--tag-keys').within(() => {
214+
cy.getByTestID('accordion-header').should('be.visible').click()
215+
})
216+
const tagKey = 'air_temp_degc'
217+
const tagValue = '70_degrees'
218+
selectListItem(tagValue, true)
219+
cy.getByTestID('sql-editor').contains(`"${tagKey}" IN ('${tagValue}')`)
220+
221+
cy.log('select tagValue --> removes from composition')
222+
selectListItem(tagValue, false)
223+
cy.wait(1000)
224+
cy.getByTestID('sql-editor').within(() => {
225+
cy.get('textarea.inputarea').should('not.contain', tagKey)
226+
})
227+
})
228+
229+
it('will empty the default text on first bucket selection', () => {
230+
cy.log('start with default text')
231+
cy.getByTestID('sql-editor').within(() => {
232+
cy.get('textarea.inputarea').should(
233+
'have.value',
234+
DEFAULT_SQL_EDITOR_TEXT
235+
)
236+
})
237+
238+
cy.log('select bucket')
239+
selectBucket(bucketName)
240+
confirmSyncIsOn() // SQL composition is dumb. On bucket selection, it will occasionally drop the sync.
241+
cy.log('writes empty query statement with only the timerange')
242+
cy.getByTestID('sql-editor').contains(`SELECT *`)
243+
cy.getByTestID('sql-editor').contains(`WHERE`)
244+
cy.getByTestID('sql-editor').contains(
245+
`time >= now() - interval '1 hour'`
246+
)
247+
248+
cy.getByTestID('sql-editor').should(
249+
'not.contain',
250+
DEFAULT_SQL_EDITOR_TEXT
251+
)
252+
})
253+
})
254+
255+
describe('sync and resetting behavior:', () => {
256+
it('sync defaults to on. Can be toggled on/off. And can diverge (be disabled).', () => {
257+
cy.log('starts as synced')
258+
cy.getByTestID('editor-sync--toggle').should('have.class', 'active')
259+
260+
cy.log('empty editor text')
261+
cy.getByTestID('sql-editor').monacoType('{selectAll}{del}')
262+
263+
cy.log('make a composition')
264+
selectSchema()
265+
confirmSyncIsOn() // SQL composition is dumb. On bucket selection, it will occasionally drop the sync.
266+
confirmSchemaComposition()
267+
268+
cy.log('sync toggles on and off, with matching styles')
269+
cy.get('.composition-sync--on').should('have.length', 4)
270+
cy.get('.composition-sync--off').should('have.length', 0)
271+
cy.getByTestID('editor-sync--toggle')
272+
.should('have.class', 'active')
273+
.click()
274+
.should('not.have.class', 'active')
275+
cy.get('.composition-sync--on').should('have.length', 0)
276+
cy.get('.composition-sync--off').should('have.length', 4)
277+
cy.getByTestID('editor-sync--toggle')
278+
.click()
279+
.should('have.class', 'active')
280+
cy.get('.composition-sync--on').should('have.length', 4)
281+
cy.get('.composition-sync--off').should('have.length', 0)
282+
283+
cy.log('turn off editor sync')
284+
cy.getByTestID('editor-sync--toggle')
285+
.click()
286+
.should('not.have.class', 'active')
287+
288+
cy.log('can still browse schema while not synced')
289+
selectBucket('defbuck2')
290+
})
291+
292+
it('should clear the editor text and schema browser, with a new script', () => {
293+
cy.getByTestID('sql-editor', {timeout: DELAY_FOR_LAZY_LOAD_EDITOR})
294+
295+
cy.log('modify schema browser')
296+
selectSchema()
297+
298+
cy.log('editor text contains the composition')
299+
confirmSchemaComposition()
300+
301+
cy.log('click new script, and choose to delete current script')
302+
clearSession()
303+
})
304+
305+
it('should not be able to modify the composition when unsynced, yet still modify the session -- which updates the composition when re-synced', () => {
306+
cy.log('empty editor text')
307+
cy.getByTestID('sql-editor').monacoType('{selectall}{enter}')
308+
309+
cy.log('turn off sync')
310+
cy.getByTestID('editor-sync--toggle')
311+
.should('have.class', 'active')
312+
.click()
313+
cy.getByTestID('editor-sync--toggle').should('not.have.class', 'active')
314+
315+
cy.log('modify schema browser')
316+
selectBucket(bucketName)
317+
selectMeasurement(measurement)
318+
319+
cy.log('editor text is still empty')
320+
cy.getByTestID('sql-editor').within(() => {
321+
// selecting bucket will empty the editor text
322+
cy.get('textarea.inputarea').should('have.value', '\n')
323+
})
324+
325+
cy.log('turn on sync')
326+
cy.getByTestID('editor-sync--toggle')
327+
.should('not.have.class', 'active')
328+
.click()
329+
cy.getByTestID('editor-sync--toggle').should('have.class', 'active')
330+
331+
cy.log('editor text contains the composition')
332+
confirmSchemaComposition()
333+
})
334+
})
335+
})
336+
})

0 commit comments

Comments
 (0)