Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
cc4e8fd5
Commit
cc4e8fd5
authored
Jan 22, 2021
by
Olena Horal-Koretska
Committed by
Ezekiel Kigbo
Jan 22, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Integrate mapping creation with BE
parent
c200cda7
Changes
15
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
410 additions
and
235 deletions
+410
-235
app/assets/javascripts/alerts_settings/components/alert_mapping_builder.vue
...ipts/alerts_settings/components/alert_mapping_builder.vue
+16
-24
app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
...ripts/alerts_settings/components/alerts_settings_form.vue
+21
-5
app/assets/javascripts/alerts_settings/components/mocks/gitlabFields.json
...cripts/alerts_settings/components/mocks/gitlabFields.json
+57
-46
app/assets/javascripts/alerts_settings/components/mocks/parsedMapping.json
...ripts/alerts_settings/components/mocks/parsedMapping.json
+26
-52
app/assets/javascripts/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql
...raphql/mutations/create_http_integration.mutation.graphql
+16
-2
app/assets/javascripts/alerts_settings/utils/mapping_transformations.js
...ascripts/alerts_settings/utils/mapping_transformations.js
+63
-0
spec/frontend/alerts_settings/components/__snapshots__/alerts_settings_form_spec.js.snap
...omponents/__snapshots__/alerts_settings_form_spec.js.snap
+0
-0
spec/frontend/alerts_settings/components/alert_mapping_builder_spec.js
.../alerts_settings/components/alert_mapping_builder_spec.js
+23
-15
spec/frontend/alerts_settings/components/alerts_integrations_list_spec.js
...erts_settings/components/alerts_integrations_list_spec.js
+0
-0
spec/frontend/alerts_settings/components/alerts_settings_form_spec.js
...d/alerts_settings/components/alerts_settings_form_spec.js
+108
-91
spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js
...lerts_settings/components/alerts_settings_wrapper_spec.js
+0
-0
spec/frontend/alerts_settings/components/mocks/apollo_mock.js
.../frontend/alerts_settings/components/mocks/apollo_mock.js
+0
-0
spec/frontend/alerts_settings/components/mocks/integrations.json
...ontend/alerts_settings/components/mocks/integrations.json
+0
-0
spec/frontend/alerts_settings/components/util.js
spec/frontend/alerts_settings/components/util.js
+0
-0
spec/frontend/alerts_settings/utils/mapping_transformations_spec.js
...end/alerts_settings/utils/mapping_transformations_spec.js
+80
-0
No files found.
app/assets/javascripts/alerts_settings/components/alert_mapping_builder.vue
View file @
cc4e8fd5
...
...
@@ -13,6 +13,12 @@ import { s__, __ } from '~/locale';
// data format is defined and will be the same as mocked (maybe with some minor changes)
// feature rollout plan - https://gitlab.com/gitlab-org/gitlab/-/issues/262707#note_442529171
import
gitlabFieldsMock
from
'
./mocks/gitlabFields.json
'
;
import
{
capitalizeFirstCharacter
}
from
'
~/lib/utils/text_utility
'
;
import
{
getMappingData
,
getPayloadFields
,
transformForSave
,
}
from
'
../utils/mapping_transformations
'
;
export
const
i18n
=
{
columns
:
{
...
...
@@ -46,12 +52,12 @@ export default {
},
},
props
:
{
pa
yloadFields
:
{
pa
rsedPayload
:
{
type
:
Array
,
required
:
false
,
default
:
()
=>
[],
},
m
apping
:
{
savedM
apping
:
{
type
:
Array
,
required
:
false
,
default
:
()
=>
[],
...
...
@@ -63,27 +69,11 @@ export default {
};
},
computed
:
{
payloadFields
()
{
return
getPayloadFields
(
this
.
parsedPayload
);
},
mappingData
()
{
return
this
.
gitlabFields
.
map
((
gitlabField
)
=>
{
const
mappingFields
=
this
.
payloadFields
.
filter
(({
type
})
=>
type
.
some
((
t
)
=>
gitlabField
.
compatibleTypes
.
includes
(
t
)),
);
const
foundMapping
=
this
.
mapping
.
find
(
({
alertFieldName
})
=>
alertFieldName
===
gitlabField
.
name
,
);
const
{
fallbackAlertPaths
,
payloadAlertPaths
}
=
foundMapping
||
{};
return
{
mapping
:
payloadAlertPaths
,
fallback
:
fallbackAlertPaths
,
searchTerm
:
''
,
fallbackSearchTerm
:
''
,
mappingFields
,
...
gitlabField
,
};
});
return
getMappingData
(
this
.
gitlabFields
,
this
.
payloadFields
,
this
.
savedMapping
);
},
},
methods
:
{
...
...
@@ -91,6 +81,7 @@ export default {
const
fieldIndex
=
this
.
gitlabFields
.
findIndex
((
field
)
=>
field
.
name
===
gitlabKey
);
const
updatedField
=
{
...
this
.
gitlabFields
[
fieldIndex
],
...{
[
valueKey
]:
mappingKey
}
};
Vue
.
set
(
this
.
gitlabFields
,
fieldIndex
,
updatedField
);
this
.
$emit
(
'
onMappingUpdate
'
,
transformForSave
(
this
.
mappingData
));
},
setSearchTerm
(
search
=
''
,
searchFieldKey
,
gitlabKey
)
{
const
fieldIndex
=
this
.
gitlabFields
.
findIndex
((
field
)
=>
field
.
name
===
gitlabKey
);
...
...
@@ -99,7 +90,6 @@ export default {
},
filterFields
(
searchTerm
=
''
,
fields
)
{
const
search
=
searchTerm
.
toLowerCase
();
return
fields
.
filter
((
field
)
=>
field
.
label
.
toLowerCase
().
includes
(
search
));
},
isSelected
(
fieldValue
,
mapping
)
{
...
...
@@ -112,7 +102,9 @@ export default {
);
},
getFieldValue
({
label
,
type
})
{
return
`
${
label
}
(
${
type
.
join
(
__
(
'
or
'
))}
)`
;
const
types
=
type
.
map
((
t
)
=>
capitalizeFirstCharacter
(
t
.
toLowerCase
())).
join
(
__
(
'
or
'
));
return
`
${
label
}
(
${
types
}
)`
;
},
noResults
(
searchTerm
,
fields
)
{
return
!
this
.
filterFields
(
searchTerm
,
fields
).
length
;
...
...
app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
View file @
cc4e8fd5
...
...
@@ -152,6 +152,7 @@ export default {
},
resetSamplePayloadConfirmed
:
false
,
customMapping
:
null
,
mapping
:
[],
parsingPayload
:
false
,
currentIntegration
:
null
,
};
...
...
@@ -199,10 +200,10 @@ export default {
this
.
selectedIntegration
===
typeSet
.
http
);
},
mappingBuilderFields
()
{
parsedSamplePayload
()
{
return
this
.
customMapping
?.
samplePayload
?.
payloadAlerFields
?.
nodes
;
},
mappingBuilder
Mapping
()
{
saved
Mapping
()
{
return
this
.
customMapping
?.
storedMapping
?.
nodes
;
},
hasSamplePayload
()
{
...
...
@@ -255,9 +256,20 @@ export default {
},
submit
()
{
const
{
name
,
apiUrl
}
=
this
.
integrationForm
;
const
customMappingVariables
=
this
.
glFeatures
.
multipleHttpIntegrationsCustomMapping
?
{
payloadAttributeMappings
:
this
.
mapping
,
payloadExample
:
this
.
integrationTestPayload
.
json
,
}
:
{};
const
variables
=
this
.
selectedIntegration
===
typeSet
.
http
?
{
name
,
active
:
this
.
active
}
?
{
name
,
active
:
this
.
active
,
...
customMappingVariables
,
}
:
{
apiUrl
,
active
:
this
.
active
};
const
integrationPayload
=
{
type
:
this
.
selectedIntegration
,
variables
};
...
...
@@ -336,6 +348,9 @@ export default {
this
.
integrationTestPayload
.
json
=
res
?.
samplePayload
.
body
;
});
},
updateMapping
(
mapping
)
{
this
.
mapping
=
mapping
;
},
},
};
</
script
>
...
...
@@ -541,8 +556,9 @@ export default {
>
<span>
{{ $options.i18n.integrationFormSteps.step5.intro }}
</span>
<mapping-builder
:payload-fields=
"mappingBuilderFields"
:mapping=
"mappingBuilderMapping"
:parsed-payload=
"parsedSamplePayload"
:saved-mapping=
"savedMapping"
@
onMappingUpdate=
"updateMapping"
/>
</gl-form-group>
</div>
...
...
app/assets/javascripts/alerts_settings/components/mocks/gitlabFields.json
View file @
cc4e8fd5
[
{
"name"
:
"
title
"
,
"name"
:
"
TITLE
"
,
"label"
:
"Title"
,
"type"
:
[
"S
tring
"
"S
TRING
"
],
"compatibleTypes"
:
[
"S
tring
"
,
"N
umber
"
,
"D
ateTime
"
"S
TRING
"
,
"N
UMBER
"
,
"D
ATETIME
"
],
"numberOfFallbacks"
:
1
},
{
"name"
:
"
description
"
,
"name"
:
"
DESCRIPTION
"
,
"label"
:
"Description"
,
"type"
:
[
"S
tring
"
"S
TRING
"
],
"compatibleTypes"
:
[
"S
tring
"
,
"N
umber
"
,
"D
ateTime
"
"S
TRING
"
,
"N
UMBER
"
,
"D
ATETIME
"
]
},
{
"name"
:
"
startTime
"
,
"name"
:
"
START_TIME
"
,
"label"
:
"Start time"
,
"type"
:
[
"D
ateTime
"
"D
ATETIME
"
],
"compatibleTypes"
:
[
"N
umber
"
,
"D
ateTime
"
"N
UMBER
"
,
"D
ATETIME
"
]
},
{
"name"
:
"service"
,
"name"
:
"END_TIME"
,
"label"
:
"End time"
,
"type"
:
[
"DATETIME"
],
"compatibleTypes"
:
[
"NUMBER"
,
"DATETIME"
]
},
{
"name"
:
"SERVICE"
,
"label"
:
"Service"
,
"type"
:
[
"S
tring
"
"S
TRING
"
],
"compatibleTypes"
:
[
"S
tring
"
,
"N
umber
"
,
"D
ateTime
"
"S
TRING
"
,
"N
UMBER
"
,
"D
ATETIME
"
]
},
{
"name"
:
"
monitoringTool
"
,
"name"
:
"
MONITORING_TOOL
"
,
"label"
:
"Monitoring tool"
,
"type"
:
[
"S
tring
"
"S
TRING
"
],
"compatibleTypes"
:
[
"S
tring
"
,
"N
umber
"
,
"D
ateTime
"
"S
TRING
"
,
"N
UMBER
"
,
"D
ATETIME
"
]
},
{
"name"
:
"
hosts
"
,
"name"
:
"
HOSTS
"
,
"label"
:
"Hosts"
,
"type"
:
[
"S
tring
"
,
"A
rray
"
"S
TRING
"
,
"A
RRAY
"
],
"compatibleTypes"
:
[
"S
tring
"
,
"A
rray
"
,
"N
umber
"
,
"D
ateTime
"
"S
TRING
"
,
"A
RRAY
"
,
"N
UMBER
"
,
"D
ATETIME
"
]
},
{
"name"
:
"
severity
"
,
"name"
:
"
SEVERITY
"
,
"label"
:
"Severity"
,
"type"
:
[
"S
tring
"
"S
TRING
"
],
"compatibleTypes"
:
[
"S
tring
"
,
"N
umber
"
,
"D
ateTime
"
"S
TRING
"
,
"N
UMBER
"
,
"D
ATETIME
"
]
},
{
"name"
:
"
fingerprint
"
,
"name"
:
"
FINGERPRINT
"
,
"label"
:
"Fingerprint"
,
"type"
:
[
"S
tring
"
"S
TRING
"
],
"compatibleTypes"
:
[
"S
tring
"
,
"N
umber
"
,
"D
ateTime
"
"S
TRING
"
,
"N
UMBER
"
,
"D
ATETIME
"
]
},
{
"name"
:
"
environment
"
,
"name"
:
"
GITLAB_ENVIRONMENT_NAME
"
,
"label"
:
"Environment"
,
"type"
:
[
"S
tring
"
"S
TRING
"
],
"compatibleTypes"
:
[
"S
tring
"
,
"N
umber
"
,
"D
ateTime
"
"S
TRING
"
,
"N
UMBER
"
,
"D
ATETIME
"
]
}
]
app/assets/javascripts/alerts_settings/components/mocks/parsedMapping.json
View file @
cc4e8fd5
...
...
@@ -4,95 +4,69 @@
"payloadAlerFields"
:
{
"nodes"
:
[
{
"
name"
:
"dashboardId"
,
"
path"
:
[
"dashboardId"
]
,
"label"
:
"Dashboard Id"
,
"type"
:
[
"Number"
]
"type"
:
"STRING"
},
{
"
name"
:
"evalMatches"
,
"
path"
:
[
"evalMatches"
]
,
"label"
:
"Eval Matches"
,
"type"
:
[
"Array"
]
"type"
:
"ARRAY"
},
{
"
name"
:
"createdAt"
,
"
path"
:
[
"createdAt"
]
,
"label"
:
"Created At"
,
"type"
:
[
"DateTime"
]
"type"
:
"DATETIME"
},
{
"
name"
:
"imageUrl"
,
"
path"
:
[
"imageUrl"
]
,
"label"
:
"Image Url"
,
"type"
:
[
"String"
]
"type"
:
"STRING"
},
{
"
name"
:
"message"
,
"
path"
:
[
"message"
]
,
"label"
:
"Message"
,
"type"
:
[
"String"
]
"type"
:
"STRING"
},
{
"
name"
:
"orgId"
,
"
path"
:
[
"orgId"
]
,
"label"
:
"Org Id"
,
"type"
:
[
"Number"
]
"type"
:
"STRING"
},
{
"
name"
:
"panelId"
,
"
path"
:
[
"panelId"
]
,
"label"
:
"Panel Id"
,
"type"
:
[
"String"
]
"type"
:
"STRING"
},
{
"
name"
:
"ruleId"
,
"
path"
:
[
"ruleId"
]
,
"label"
:
"Rule Id"
,
"type"
:
[
"Number"
]
"type"
:
"STRING"
},
{
"
name"
:
"ruleName"
,
"
path"
:
[
"ruleName"
]
,
"label"
:
"Rule Name"
,
"type"
:
[
"String"
]
"type"
:
"STRING"
},
{
"
name"
:
"ruleUrl"
,
"
path"
:
[
"ruleUrl"
]
,
"label"
:
"Rule Url"
,
"type"
:
[
"String"
]
"type"
:
"STRING"
},
{
"
name"
:
"state"
,
"
path"
:
[
"state"
]
,
"label"
:
"State"
,
"type"
:
[
"String"
]
"type"
:
"STRING"
},
{
"
name"
:
"title"
,
"
path"
:
[
"title"
]
,
"label"
:
"Title"
,
"type"
:
[
"String"
]
"type"
:
"STRING"
},
{
"
name"
:
"tags"
,
"
path"
:
[
"tags"
,
"tag"
]
,
"label"
:
"Tags"
,
"type"
:
[
"Object"
]
"type"
:
"STRING"
}
]
}
...
...
app/assets/javascripts/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql
View file @
cc4e8fd5
#import "../fragments/integration_item.fragment.graphql"
mutation
createHttpIntegration
(
$projectPath
:
ID
!,
$name
:
String
!,
$active
:
Boolean
!)
{
httpIntegrationCreate
(
input
:
{
projectPath
:
$projectPath
,
name
:
$name
,
active
:
$active
})
{
mutation
createHttpIntegration
(
$projectPath
:
ID
!
$name
:
String
!
$active
:
Boolean
!
$payloadExample
:
JsonString
$payloadAttributeMappings
:
[
AlertManagementPayloadAlertFieldInput
!]
)
{
httpIntegrationCreate
(
input
:
{
projectPath
:
$projectPath
name
:
$name
active
:
$active
payloadExample
:
$payloadExample
payloadAttributeMappings
:
$payloadAttributeMappings
}
)
{
errors
integration
{
...
IntegrationItem
...
...
app/assets/javascripts/alerts_settings/utils/mapping_transformations.js
0 → 100644
View file @
cc4e8fd5
/**
* Given data for GitLab alert fields, parsed payload fields data and previously stored mapping (if any)
* creates an object in a form convenient to build UI && interact with it
* @param {Object} gitlabFields - structure describing GitLab alert fields
* @param {Object} payloadFields - parsed from sample JSON sample alert fields
* @param {Object} savedMapping - GitLab fields to parsed fields mapping
*
* @return {Object} mapping data for UI mapping builder
*/
export
const
getMappingData
=
(
gitlabFields
,
payloadFields
,
savedMapping
)
=>
{
return
gitlabFields
.
map
((
gitlabField
)
=>
{
// find fields from payload that match gitlab alert field by type
const
mappingFields
=
payloadFields
.
filter
(({
type
})
=>
gitlabField
.
compatibleTypes
.
includes
(
type
),
);
// find the mapping that was previously stored
const
foundMapping
=
savedMapping
.
find
(({
fieldName
})
=>
fieldName
===
gitlabField
.
name
);
const
{
fallbackAlertPaths
,
payloadAlertPaths
}
=
foundMapping
||
{};
return
{
mapping
:
payloadAlertPaths
,
fallback
:
fallbackAlertPaths
,
searchTerm
:
''
,
fallbackSearchTerm
:
''
,
mappingFields
,
...
gitlabField
,
};
});
};
/**
* Based on mapping data configured by the user creates an object in a format suitable for save on BE
* @param {Object} mappingData - structure describing mapping between GitLab fields and parsed payload fields
*
* @return {Object} mapping data to send to BE
*/
export
const
transformForSave
=
(
mappingData
)
=>
{
return
mappingData
.
reduce
((
acc
,
field
)
=>
{
const
mapped
=
field
.
mappingFields
.
find
(({
name
})
=>
name
===
field
.
mapping
);
if
(
mapped
)
{
const
{
path
,
type
,
label
}
=
mapped
;
acc
.
push
({
fieldName
:
field
.
name
,
path
,
type
,
label
,
});
}
return
acc
;
},
[]);
};
/**
* Adds `name` prop to each provided by BE parsed payload field
* @param {Object} payload - parsed sample payload
*
* @return {Object} same as input with an extra `name` property which basically serves as a key to make a match
*/
export
const
getPayloadFields
=
(
payload
)
=>
{
return
payload
.
map
((
field
)
=>
({
...
field
,
name
:
field
.
path
.
join
(
'
_
'
)
}));
};
spec/frontend/alerts_settings/__snapshots__/alerts_settings_form_spec.js.snap
→
spec/frontend/alerts_settings/
components/
__snapshots__/alerts_settings_form_spec.js.snap
View file @
cc4e8fd5
File moved
spec/frontend/alerts_settings/alert_mapping_builder_spec.js
→
spec/frontend/alerts_settings/
components/
alert_mapping_builder_spec.js
View file @
cc4e8fd5
...
...
@@ -3,6 +3,8 @@ import { shallowMount } from '@vue/test-utils';
import
AlertMappingBuilder
,
{
i18n
}
from
'
~/alerts_settings/components/alert_mapping_builder.vue
'
;
import
gitlabFields
from
'
~/alerts_settings/components/mocks/gitlabFields.json
'
;
import
parsedMapping
from
'
~/alerts_settings/components/mocks/parsedMapping.json
'
;
import
{
capitalizeFirstCharacter
}
from
'
~/lib/utils/text_utility
'
;
import
*
as
transformationUtils
from
'
~/alerts_settings/utils/mapping_transformations
'
;
describe
(
'
AlertMappingBuilder
'
,
()
=>
{
let
wrapper
;
...
...
@@ -10,8 +12,8 @@ describe('AlertMappingBuilder', () => {
function
mountComponent
()
{
wrapper
=
shallowMount
(
AlertMappingBuilder
,
{
propsData
:
{
pa
yloadFields
:
parsedMapping
.
samplePayload
.
payloadAlerFields
.
nodes
,
m
apping
:
parsedMapping
.
storedMapping
.
nodes
,
pa
rsedPayload
:
parsedMapping
.
samplePayload
.
payloadAlerFields
.
nodes
,
savedM
apping
:
parsedMapping
.
storedMapping
.
nodes
,
},
});
}
...
...
@@ -44,7 +46,8 @@ describe('AlertMappingBuilder', () => {
it
(
'
renders disabled form input for each mapped field
'
,
()
=>
{
gitlabFields
.
forEach
((
field
,
index
)
=>
{
const
input
=
findColumnInRow
(
index
+
1
,
0
).
find
(
GlFormInput
);
expect
(
input
.
attributes
(
'
value
'
)).
toBe
(
`
${
field
.
label
}
(
${
field
.
type
.
join
(
'
or
'
)}
)`
);
const
types
=
field
.
type
.
map
((
t
)
=>
capitalizeFirstCharacter
(
t
.
toLowerCase
())).
join
(
'
or
'
);
expect
(
input
.
attributes
(
'
value
'
)).
toBe
(
`
${
field
.
label
}
(
${
types
}
)`
);
expect
(
input
.
attributes
(
'
disabled
'
)).
toBe
(
''
);
});
});
...
...
@@ -59,16 +62,14 @@ describe('AlertMappingBuilder', () => {
it
(
'
renders mapping dropdown for each field
'
,
()
=>
{
gitlabFields
.
forEach
(({
compatibleTypes
},
index
)
=>
{
const
dropdown
=
findColumnInRow
(
index
+
1
,
2
).
find
(
GlDropdown
);
const
searchBox
=
dropdown
.
find
(
GlSearchBoxByType
);
const
dropdownItems
=
dropdown
.
findAll
(
GlDropdownItem
);
const
searchBox
=
dropdown
.
find
Component
(
GlSearchBoxByType
);
const
dropdownItems
=
dropdown
.
findAll
Components
(
GlDropdownItem
);
const
{
nodes
}
=
parsedMapping
.
samplePayload
.
payloadAlerFields
;
const
numberOfMappingOptions
=
nodes
.
filter
(({
type
})
=>
type
.
some
((
t
)
=>
compatibleTypes
.
includes
(
t
)),
);
const
mappingOptions
=
nodes
.
filter
(({
type
})
=>
compatibleTypes
.
includes
(
type
));
expect
(
dropdown
.
exists
()).
toBe
(
true
);
expect
(
searchBox
.
exists
()).
toBe
(
true
);
expect
(
dropdownItems
).
toHaveLength
(
numberOfM
appingOptions
.
length
);
expect
(
dropdownItems
).
toHaveLength
(
m
appingOptions
.
length
);
});
});
...
...
@@ -78,16 +79,23 @@ describe('AlertMappingBuilder', () => {
expect
(
dropdown
.
exists
()).
toBe
(
Boolean
(
numberOfFallbacks
));
if
(
numberOfFallbacks
)
{
const
searchBox
=
dropdown
.
find
(
GlSearchBoxByType
);
const
dropdownItems
=
dropdown
.
findAll
(
GlDropdownItem
);
const
searchBox
=
dropdown
.
find
Component
(
GlSearchBoxByType
);
const
dropdownItems
=
dropdown
.
findAll
Components
(
GlDropdownItem
);
const
{
nodes
}
=
parsedMapping
.
samplePayload
.
payloadAlerFields
;
const
numberOfMappingOptions
=
nodes
.
filter
(({
type
})
=>
type
.
some
((
t
)
=>
compatibleTypes
.
includes
(
t
)),
);
const
mappingOptions
=
nodes
.
filter
(({
type
})
=>
compatibleTypes
.
includes
(
type
));
expect
(
searchBox
.
exists
()).
toBe
(
Boolean
(
numberOfFallbacks
));
expect
(
dropdownItems
).
toHaveLength
(
numberOfM
appingOptions
.
length
);
expect
(
dropdownItems
).
toHaveLength
(
m
appingOptions
.
length
);
}
});
});
it
(
'
emits event with selected mapping
'
,
()
=>
{
const
mappingToSave
=
{
fieldName
:
'
TITLE
'
,
mapping
:
'
PARSED_TITLE
'
};
jest
.
spyOn
(
transformationUtils
,
'
transformForSave
'
).
mockReturnValue
(
mappingToSave
);
const
dropdown
=
findColumnInRow
(
1
,
2
).
find
(
GlDropdown
);
const
option
=
dropdown
.
find
(
GlDropdownItem
);
option
.
vm
.
$emit
(
'
click
'
);
expect
(
wrapper
.
emitted
(
'
onMappingUpdate
'
)[
0
]).
toEqual
([
mappingToSave
]);
});
});
spec/frontend/alerts_settings/alerts_integrations_list_spec.js
→
spec/frontend/alerts_settings/
components/
alerts_integrations_list_spec.js
View file @
cc4e8fd5
File moved
spec/frontend/alerts_settings/alerts_settings_form_spec.js
→
spec/frontend/alerts_settings/
components/
alerts_settings_form_spec.js
View file @
cc4e8fd5
...
...
@@ -9,6 +9,7 @@ import {
}
from
'
@gitlab/ui
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
AlertsSettingsForm
from
'
~/alerts_settings/components/alerts_settings_form.vue
'
;
import
MappingBuilder
from
'
~/alerts_settings/components/alert_mapping_builder.vue
'
;
import
{
defaultAlertSettingsConfig
}
from
'
./util
'
;
import
{
typeSet
}
from
'
~/alerts_settings/constants
'
;
...
...
@@ -49,6 +50,7 @@ describe('AlertsSettingsFormNew', () => {
const
findFormToggle
=
()
=>
wrapper
.
find
(
GlToggle
);
const
findTestPayloadSection
=
()
=>
wrapper
.
find
(
`[id = "test-integration"]`
);
const
findMappingBuilderSection
=
()
=>
wrapper
.
find
(
`[id = "mapping-builder"]`
);
const
findMappingBuilder
=
()
=>
wrapper
.
findComponent
(
MappingBuilder
);
const
findSubmitButton
=
()
=>
wrapper
.
find
(
`[type = "submit"]`
);
const
findMultiSupportText
=
()
=>
wrapper
.
find
(
`[data-testid="multi-integrations-not-supported"]`
);
...
...
@@ -63,6 +65,16 @@ describe('AlertsSettingsFormNew', () => {
}
});
const
selectOptionAtIndex
=
async
(
index
)
=>
{
const
options
=
findSelect
().
findAll
(
'
option
'
);
await
options
.
at
(
index
).
setSelected
();
};
const
enableIntegration
=
(
index
,
value
)
=>
{
findFormFields
().
at
(
index
).
setValue
(
value
);
findFormToggle
().
trigger
(
'
click
'
);
};
describe
(
'
with default values
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
();
...
...
@@ -80,10 +92,7 @@ describe('AlertsSettingsFormNew', () => {
});
it
(
'
shows the rest of the form when the dropdown is used
'
,
async
()
=>
{
const
options
=
findSelect
().
findAll
(
'
option
'
);
await
options
.
at
(
1
).
setSelected
();
await
wrapper
.
vm
.
$nextTick
();
await
selectOptionAtIndex
(
1
);
expect
(
findFormFields
().
at
(
0
).
isVisible
()).
toBe
(
true
);
});
...
...
@@ -96,64 +105,58 @@ describe('AlertsSettingsFormNew', () => {
it
(
'
disabled the name input when the selected value is prometheus
'
,
async
()
=>
{
createComponent
();
const
options
=
findSelect
().
findAll
(
'
option
'
);
await
options
.
at
(
2
).
setSelected
();
await
selectOptionAtIndex
(
2
);
expect
(
findFormFields
().
at
(
0
).
attributes
(
'
disabled
'
)).
toBe
(
'
disabled
'
);
});
});
describe
(
'
submitting integration form
'
,
()
=>
{
it
(
'
allows for create-new-integration with the correct form values for HTTP
'
,
async
()
=>
{
describe
(
'
HTTP
'
,
()
=>
{
it
(
'
create
'
,
async
()
=>
{
createComponent
();
const
options
=
findSelect
().
findAll
(
'
option
'
);
await
options
.
at
(
1
).
setSelected
();
await
findFormFields
().
at
(
0
).
setValue
(
'
Test integration
'
);
await
findFormToggle
().
trigger
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
const
integrationName
=
'
Test integration
'
;
await
selectOptionAtIndex
(
1
);
enableIntegration
(
0
,
integrationName
);
expect
(
findSubmitButton
().
exists
()).
toBe
(
true
);
expect
(
findSubmitButton
().
text
()).
toBe
(
'
Save integration
'
);
const
submitBtn
=
findSubmitButton
();
expect
(
submitBtn
.
exists
()).
toBe
(
true
);
expect
(
submitBtn
.
text
()).
toBe
(
'
Save integration
'
);
findForm
().
trigger
(
'
submit
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
wrapper
.
emitted
(
'
create-new-integration
'
)).
toBeTruthy
();
expect
(
wrapper
.
emitted
(
'
create-new-integration
'
)[
0
]).
toEqual
([
{
type
:
typeSet
.
http
,
variables
:
{
name
:
'
Test integration
'
,
active
:
true
}
},
{
type
:
typeSet
.
http
,
variables
:
{
name
:
integrationName
,
active
:
true
}
},
]);
});
it
(
'
allows for create-new-integration with the correct form values for PROMETHEUS
'
,
async
()
=>
{
createComponent
();
const
options
=
findSelect
().
findAll
(
'
option
'
);
await
options
.
at
(
2
).
setSelected
();
await
findFormFields
().
at
(
0
).
setValue
(
'
Test integration
'
);
await
findFormFields
().
at
(
1
).
setValue
(
'
https://test.com
'
);
await
findFormToggle
().
trigger
(
'
click
'
);
it
(
'
create with custom mapping
'
,
async
()
=>
{
createComponent
({
multipleHttpIntegrationsCustomMapping
:
true
});
await
wrapper
.
vm
.
$nextTick
();
const
integrationName
=
'
Test integration
'
;
await
selectOptionAtIndex
(
1
);
expect
(
findSubmitButton
().
exists
()).
toBe
(
true
);
expect
(
findSubmitButton
().
text
()).
toBe
(
'
Save integration
'
);
enableIntegration
(
0
,
integrationName
);
const
sampleMapping
=
{
field
:
'
test
'
};
findMappingBuilder
().
vm
.
$emit
(
'
onMappingUpdate
'
,
sampleMapping
);
findForm
().
trigger
(
'
submit
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
wrapper
.
emitted
(
'
create-new-integration
'
)).
toBeTruthy
();
expect
(
wrapper
.
emitted
(
'
create-new-integration
'
)[
0
]).
toEqual
([
{
type
:
typeSet
.
prometheus
,
variables
:
{
apiUrl
:
'
https://test.com
'
,
active
:
true
}
},
{
type
:
typeSet
.
http
,
variables
:
{
name
:
integrationName
,
active
:
true
,
payloadAttributeMappings
:
sampleMapping
,
payloadExample
:
null
,
},
},
]);
});
it
(
'
allows for update-integration with the correct form values for HTTP
'
,
async
()
=>
{
it
(
'
update
'
,
()
=>
{
createComponent
({
data
:
{
selectedIntegration
:
typeSet
.
http
,
...
...
@@ -163,26 +166,44 @@ describe('AlertsSettingsFormNew', () => {
loading
:
false
,
},
});
const
updatedIntegrationName
=
'
Test integration post
'
;
enableIntegration
(
0
,
updatedIntegrationName
);
await
findFormFields
().
at
(
0
).
setValue
(
'
Test integration post
'
);
await
findFormToggle
().
trigger
(
'
click
'
);
const
submitBtn
=
findSubmitButton
();
expect
(
submitBtn
.
exists
()).
toBe
(
true
);
expect
(
submitBtn
.
text
()).
toBe
(
'
Save integration
'
);
await
wrapper
.
vm
.
$nextTick
(
);
findForm
().
trigger
(
'
submit
'
);
expect
(
findSubmitButton
().
exists
()).
toBe
(
true
);
expect
(
findSubmitButton
().
text
()).
toBe
(
'
Save integration
'
);
expect
(
wrapper
.
emitted
(
'
update-integration
'
)[
0
]).
toEqual
([
{
type
:
typeSet
.
http
,
variables
:
{
name
:
updatedIntegrationName
,
active
:
true
}
},
]);
});
});
findForm
().
trigger
(
'
submit
'
);
describe
(
'
PROMETHEUS
'
,
()
=>
{
it
(
'
create
'
,
async
()
=>
{
createComponent
();
await
wrapper
.
vm
.
$nextTick
(
);
await
selectOptionAtIndex
(
2
);
expect
(
wrapper
.
emitted
(
'
update-integration
'
)).
toBeTruthy
();
expect
(
wrapper
.
emitted
(
'
update-integration
'
)[
0
]).
toEqual
([
{
type
:
typeSet
.
http
,
variables
:
{
name
:
'
Test integration post
'
,
active
:
true
}
},
const
apiUrl
=
'
https://test.com
'
;
enableIntegration
(
1
,
apiUrl
);
findFormToggle
().
trigger
(
'
click
'
);
const
submitBtn
=
findSubmitButton
();
expect
(
submitBtn
.
exists
()).
toBe
(
true
);
expect
(
submitBtn
.
text
()).
toBe
(
'
Save integration
'
);
findForm
().
trigger
(
'
submit
'
);
expect
(
wrapper
.
emitted
(
'
create-new-integration
'
)[
0
]).
toEqual
([
{
type
:
typeSet
.
prometheus
,
variables
:
{
apiUrl
,
active
:
true
}
},
]);
});
it
(
'
allows for update-integration with the correct form values for PROMETHEUS
'
,
async
()
=>
{
it
(
'
update
'
,
()
=>
{
createComponent
({
data
:
{
selectedIntegration
:
typeSet
.
prometheus
,
...
...
@@ -193,25 +214,21 @@ describe('AlertsSettingsFormNew', () => {
},
});
await
findFormFields
().
at
(
0
).
setValue
(
'
Test integration
'
);
await
findFormFields
().
at
(
1
).
setValue
(
'
https://test-post.com
'
);
await
findFormToggle
().
trigger
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
const
apiUrl
=
'
https://test-post.com
'
;
enableIntegration
(
1
,
apiUrl
);
expect
(
findSubmitButton
().
exists
()).
toBe
(
true
);
expect
(
findSubmitButton
().
text
()).
toBe
(
'
Save integration
'
);
const
submitBtn
=
findSubmitButton
();
expect
(
submitBtn
.
exists
()).
toBe
(
true
);
expect
(
submitBtn
.
text
()).
toBe
(
'
Save integration
'
);
findForm
().
trigger
(
'
submit
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
wrapper
.
emitted
(
'
update-integration
'
)).
toBeTruthy
();
expect
(
wrapper
.
emitted
(
'
update-integration
'
)[
0
]).
toEqual
([
{
type
:
typeSet
.
prometheus
,
variables
:
{
apiUrl
:
'
https://test-post.com
'
,
active
:
true
}
},
{
type
:
typeSet
.
prometheus
,
variables
:
{
apiUrl
,
active
:
true
}
},
]);
});
});
});
describe
(
'
submitting the integration with a JSON test payload
'
,
()
=>
{
beforeEach
(()
=>
{
...
...
@@ -234,9 +251,10 @@ describe('AlertsSettingsFormNew', () => {
jest
.
runAllTimers
();
await
wrapper
.
vm
.
$nextTick
();
expect
(
findJsonTestSubmit
().
exists
()).
toBe
(
true
);
expect
(
findJsonTestSubmit
().
text
()).
toBe
(
'
Save and test payload
'
);
expect
(
findJsonTestSubmit
().
props
(
'
disabled
'
)).
toBe
(
true
);
const
jsonTestSubmit
=
findJsonTestSubmit
();
expect
(
jsonTestSubmit
.
exists
()).
toBe
(
true
);
expect
(
jsonTestSubmit
.
text
()).
toBe
(
'
Save and test payload
'
);
expect
(
jsonTestSubmit
.
props
(
'
disabled
'
)).
toBe
(
true
);
});
it
(
'
should allow for the form to be automatically saved if the test payload is successfully submitted
'
,
async
()
=>
{
...
...
@@ -341,9 +359,8 @@ describe('AlertsSettingsFormNew', () => {
it
(
`
${
visibleMsg
}
when multipleHttpIntegrationsCustomMapping feature flag
${
featureFlagMsg
}
and integration type is
${
integrationType
}
`
,
async
()
=>
{
createComponent
({
multipleHttpIntegrationsCustomMapping
:
featureFlag
});
const
options
=
findSelect
().
findAll
(
'
option
'
);
options
.
at
(
integrationOption
).
setSelected
();
await
wrapper
.
vm
.
$nextTick
();
await
selectOptionAtIndex
(
integrationOption
);
expect
(
findMappingBuilderSection
().
exists
()).
toBe
(
visible
);
});
});
...
...
spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js
→
spec/frontend/alerts_settings/
components/
alerts_settings_wrapper_spec.js
View file @
cc4e8fd5
File moved
spec/frontend/alerts_settings/mocks/apollo_mock.js
→
spec/frontend/alerts_settings/
components/
mocks/apollo_mock.js
View file @
cc4e8fd5
File moved
spec/frontend/alerts_settings/mocks/integrations.json
→
spec/frontend/alerts_settings/
components/
mocks/integrations.json
View file @
cc4e8fd5
File moved
spec/frontend/alerts_settings/util.js
→
spec/frontend/alerts_settings/
components/
util.js
View file @
cc4e8fd5
File moved
spec/frontend/alerts_settings/utils/mapping_transformations_spec.js
0 → 100644
View file @
cc4e8fd5
import
{
getMappingData
,
getPayloadFields
,
transformForSave
,
}
from
'
~/alerts_settings/utils/mapping_transformations
'
;
import
gitlabFieldsMock
from
'
~/alerts_settings/components/mocks/gitlabFields.json
'
;
import
parsedMapping
from
'
~/alerts_settings/components/mocks/parsedMapping.json
'
;
describe
(
'
Mapping Transformation Utilities
'
,
()
=>
{
const
nameField
=
{
label
:
'
Name
'
,
path
:
[
'
alert
'
,
'
name
'
],
type
:
'
STRING
'
,
};
const
dashboardField
=
{
label
:
'
Dashboard Id
'
,
path
:
[
'
alert
'
,
'
dashboardId
'
],
type
:
'
STRING
'
,
};
describe
(
'
getMappingData
'
,
()
=>
{
it
(
'
should return mapping data
'
,
()
=>
{
const
alertFields
=
gitlabFieldsMock
.
slice
(
0
,
3
);
const
result
=
getMappingData
(
alertFields
,
getPayloadFields
(
parsedMapping
.
samplePayload
.
payloadAlerFields
.
nodes
.
slice
(
0
,
3
)),
parsedMapping
.
storedMapping
.
nodes
.
slice
(
0
,
3
),
);
result
.
forEach
((
data
,
index
)
=>
{
expect
(
data
).
toEqual
(
expect
.
objectContaining
({
...
alertFields
[
index
],
searchTerm
:
''
,
fallbackSearchTerm
:
''
,
}),
);
});
});
});
describe
(
'
transformForSave
'
,
()
=>
{
it
(
'
should transform mapped data for save
'
,
()
=>
{
const
fieldName
=
'
title
'
;
const
mockMappingData
=
[
{
name
:
fieldName
,
mapping
:
'
alert_name
'
,
mappingFields
:
getPayloadFields
([
dashboardField
,
nameField
]),
},
];
const
result
=
transformForSave
(
mockMappingData
);
const
{
path
,
type
,
label
}
=
nameField
;
expect
(
result
).
toEqual
([{
fieldName
,
path
,
type
,
label
}]);
});
it
(
'
should return empty array if no mapping provided
'
,
()
=>
{
const
fieldName
=
'
title
'
;
const
mockMappingData
=
[
{
name
:
fieldName
,
mapping
:
null
,
mappingFields
:
getPayloadFields
([
nameField
,
dashboardField
]),
},
];
const
result
=
transformForSave
(
mockMappingData
);
expect
(
result
).
toEqual
([]);
});
});
describe
(
'
getPayloadFields
'
,
()
=>
{
it
(
'
should add name field to each payload field
'
,
()
=>
{
const
result
=
getPayloadFields
([
nameField
,
dashboardField
]);
expect
(
result
).
toEqual
([
{
...
nameField
,
name
:
'
alert_name
'
},
{
...
dashboardField
,
name
:
'
alert_dashboardId
'
},
]);
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment