Skip to content

Commit b1aefb7

Browse files
[9.0] Add FTR cases for synonyms (elastic#214476) (elastic#214999)
# Backport This will backport the following commits from `main` to `9.0`: - [Add FTR cases for synonyms (elastic#214476)](elastic#214476) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Efe Gürkan YALAMAN","email":"[email protected]"},"sourceCommit":{"committedDate":"2025-03-18T15:25:48Z","message":"Add FTR cases for synonyms (elastic#214476)\n\n## Summary\n\nAdds more coverage for FTRs to test Synonyms UI in serverless.\n\nAdds test cases for synonyms set listing, synoyms set detail and adding\ndeleting rules.\nCovers some happy paths.\n\n\n### Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers should verify this PR satisfies this list as well.\n\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [x] This was checked for breaking HTTP API changes, and any breaking\nchanges have been approved by the breaking-change committee. The\n`release_note:breaking` label should be applied in these situations.\n- [ ] [Flaky Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\nused on any tests changed\n- [x] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"a73477c7c05ffd748f1fdce58184d837b153798e","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Search","backport:version","v9.1.0","v9.0.1"],"title":"Add FTR cases for synonyms","number":214476,"url":"https://github.com/elastic/kibana/pull/214476","mergeCommit":{"message":"Add FTR cases for synonyms (elastic#214476)\n\n## Summary\n\nAdds more coverage for FTRs to test Synonyms UI in serverless.\n\nAdds test cases for synonyms set listing, synoyms set detail and adding\ndeleting rules.\nCovers some happy paths.\n\n\n### Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers should verify this PR satisfies this list as well.\n\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [x] This was checked for breaking HTTP API changes, and any breaking\nchanges have been approved by the breaking-change committee. The\n`release_note:breaking` label should be applied in these situations.\n- [ ] [Flaky Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\nused on any tests changed\n- [x] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"a73477c7c05ffd748f1fdce58184d837b153798e"}},"sourceBranch":"main","suggestedTargetBranches":["9.0"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/214476","number":214476,"mergeCommit":{"message":"Add FTR cases for synonyms (elastic#214476)\n\n## Summary\n\nAdds more coverage for FTRs to test Synonyms UI in serverless.\n\nAdds test cases for synonyms set listing, synoyms set detail and adding\ndeleting rules.\nCovers some happy paths.\n\n\n### Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers should verify this PR satisfies this list as well.\n\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [x] This was checked for breaking HTTP API changes, and any breaking\nchanges have been approved by the breaking-change committee. The\n`release_note:breaking` label should be applied in these situations.\n- [ ] [Flaky Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\nused on any tests changed\n- [x] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"a73477c7c05ffd748f1fdce58184d837b153798e"}}]}] BACKPORT--> Co-authored-by: Efe Gürkan YALAMAN <[email protected]>
1 parent 22245cb commit b1aefb7

File tree

5 files changed

+444
-5
lines changed

5 files changed

+444
-5
lines changed

x-pack/solutions/search/plugins/search_synonyms/public/components/synonyms_set_detail/synonyms_set_rule_table.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ export const SynonymsSetRuleTable = ({ synonymsSetId = '' }: { synonymsSetId: st
141141
icon: 'trash',
142142
color: 'danger',
143143
type: 'icon',
144+
'data-test-subj': 'searchSynonymsSynonymsSetTableDeleteRuleButton',
144145
onClick: (synonymRule: SynonymsSynonymRule) => {
145146
if (synonymRule.id) {
146147
setSynonymRuleToDelete(synonymRule.id);
@@ -159,6 +160,7 @@ export const SynonymsSetRuleTable = ({ synonymsSetId = '' }: { synonymsSetId: st
159160
),
160161
icon: 'pencil',
161162
type: 'icon',
163+
'data-test-subj': 'searchSynonymsSynonymsSetTableEditRuleButton',
162164
onClick: (synonymRule: SynonymsSynonymRule) => {
163165
if (synonymRule.id) {
164166
setSynonymsRuleToEdit(synonymRule.id);

x-pack/test/functional/page_objects/search_synonyms_page.ts

Lines changed: 174 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,188 @@ import { FtrProviderContext } from '../ftr_provider_context';
99

1010
export function SearchSynonymsPageProvider({ getService }: FtrProviderContext) {
1111
const testSubjects = getService('testSubjects');
12+
const find = getService('find');
1213

1314
return {
1415
SynonymsGetStartedPage: {
16+
TEST_IDS: {
17+
GET_STARTED_BUTTON: 'searchSynonymsEmptyPromptGetStartedButton',
18+
CREATE_SYNONYMS_SET_MODAL_INPUT: 'searchSynonymsCreateSynonymsSetModalFieldText',
19+
CREATE_SYNONYMS_SET_MODAL_CREATE_BUTTON: 'searchSynonymsCreateSynonymsSetModalCreateButton',
20+
CREATE_SYNONYMS_SET_MODAL_OVERWRITE_CHECKBOX:
21+
'searchSynonymsCreateSynonymsSetModalForceWrite',
22+
},
1523
async expectSynonymsGetStartedPageComponentsToExist() {
16-
await testSubjects.existOrFail('searchSynonymsEmptyPromptGetStartedButton');
24+
await testSubjects.existOrFail(this.TEST_IDS.GET_STARTED_BUTTON);
25+
},
26+
async clickCreateSynonymsSetButton() {
27+
await testSubjects.click(this.TEST_IDS.GET_STARTED_BUTTON);
28+
},
29+
async setSynonymsSetName(name: string) {
30+
await testSubjects.setValue(this.TEST_IDS.CREATE_SYNONYMS_SET_MODAL_INPUT, name);
31+
},
32+
async clickSaveButton() {
33+
await testSubjects.click(this.TEST_IDS.CREATE_SYNONYMS_SET_MODAL_CREATE_BUTTON);
34+
},
35+
async clickOverwriteCheckbox() {
36+
await testSubjects.click(this.TEST_IDS.CREATE_SYNONYMS_SET_MODAL_OVERWRITE_CHECKBOX);
1737
},
1838
},
1939
SynonymsSetsListPage: {
40+
TEST_IDS: {
41+
SYNONYMS_SET_TABLE: 'synonyms-set-table',
42+
SYNONYMS_SET_ITEM_NAME: 'synonyms-set-item-name',
43+
SYNONYMS_SET_ITEM_RULE_COUNT: 'synonyms-set-item-rule-count',
44+
PAGINATION_NEXT_BUTTON: 'pagination-button-next',
45+
PAGE_PREVIOUS_BUTTON: 'pagination-button-previous',
46+
},
47+
async getSynonymsSetsList() {
48+
const table = await testSubjects.find(this.TEST_IDS.SYNONYMS_SET_TABLE);
49+
const allRows = await table
50+
.findByTagName('tbody')
51+
.then((tbody) => tbody.findAllByTagName('tr'));
52+
53+
return Promise.all(
54+
allRows.map(async (row) => {
55+
const $ = await row.parseDomContent();
56+
return {
57+
name: $.findTestSubject(this.TEST_IDS.SYNONYMS_SET_ITEM_NAME).text().trim(),
58+
ruleCount: Number(
59+
$.findTestSubject(this.TEST_IDS.SYNONYMS_SET_ITEM_RULE_COUNT).text()
60+
),
61+
};
62+
})
63+
);
64+
},
65+
async clickSynonymsSet(name: string) {
66+
// find synonym set with name and click on it
67+
const table = await testSubjects.findAll(this.TEST_IDS.SYNONYMS_SET_ITEM_NAME);
68+
for (const item of table) {
69+
const text = await item.getVisibleText();
70+
if (text === name) {
71+
await item.click();
72+
return;
73+
}
74+
}
75+
throw new Error(`Synonyms set with name "${name}" not found`);
76+
},
2077
async expectSynonymsSetsListPageComponentsToExist() {
21-
await testSubjects.existOrFail('synonyms-set-table');
22-
await testSubjects.existOrFail('synonyms-set-item-rule-count');
78+
await testSubjects.existOrFail(this.TEST_IDS.SYNONYMS_SET_TABLE);
79+
await testSubjects.existOrFail(this.TEST_IDS.SYNONYMS_SET_ITEM_RULE_COUNT);
80+
},
81+
async clickPaginationNext() {
82+
await testSubjects.click(this.TEST_IDS.PAGINATION_NEXT_BUTTON);
83+
},
84+
async clickPaginationPrevious() {
85+
await testSubjects.click(this.TEST_IDS.PAGE_PREVIOUS_BUTTON);
86+
},
87+
},
88+
SynonymsSetDetailPage: {
89+
TEST_IDS: {
90+
EMPTY_RULES_CARDS_ADD_EQUIVALENT_RULE_BUTTON:
91+
'searchSynonymsSynonymsSetEmptyRulesCardsAddEquivalentRuleButton',
92+
EMPTY_RULES_CARDS_ADD_EXPLICIT_RULE_BUTTON:
93+
'searchSynonymsSynonymsSetEmptyRulesCardsAddExplicitRuleButton',
94+
TABLE_EXPAND_RULE_BUTTON: 'searchSynonymsColumnsButton',
95+
TABLE_FROM_RULES: 'synonyms-set-item-explicit-from',
96+
TABLE_TO_RULES: 'synonyms-set-item-explicit-to',
97+
TABLE_EQUIVALENT_RULES: 'synonyms-set-item-equivalent',
98+
RULE_ACTIONS_DELETE_BUTTON: 'searchSynonymsSynonymsSetTableDeleteRuleButton',
99+
RULE_ACTIONS_EDIT_BUTTON: 'searchSynonymsSynonymsSetTableEditRuleButton',
100+
ADD_NEW_RULE_BUTTON: 'searchSynonymsSynonymsSetRuleTableAddRuleButton',
101+
},
102+
async expectSynonymsSetDetailPageNavigated(name: string) {
103+
const h1Element = await find.byCssSelector('main header h1');
104+
const text = await h1Element.getVisibleText();
105+
if (text !== name) {
106+
throw new Error(`Expected page title to be "${name}" but got "${text}"`);
107+
}
108+
},
109+
110+
async expectEmptyPromptToExist() {
111+
await testSubjects.existOrFail(this.TEST_IDS.EMPTY_RULES_CARDS_ADD_EQUIVALENT_RULE_BUTTON);
112+
await testSubjects.existOrFail(this.TEST_IDS.EMPTY_RULES_CARDS_ADD_EXPLICIT_RULE_BUTTON);
113+
},
114+
async getSynonymsRules() {
115+
const table = await testSubjects.find('synonyms-set-table');
116+
const allRows = await table
117+
.findByTagName('tbody')
118+
.then((tbody) => tbody.findAllByTagName('tr'));
119+
120+
return Promise.all(
121+
allRows.map(async (row) => {
122+
const $ = await row.parseDomContent();
123+
if ($.findTestSubject('synonyms-set-item-explicit-from').length > 0) {
124+
return {
125+
synonyms: `${$.findTestSubject('synonyms-set-item-explicit-from')
126+
.text()
127+
.trim()} => ${$.findTestSubject('synonyms-set-item-explicit-to').text().trim()}`,
128+
};
129+
} else {
130+
return {
131+
synonyms: $.findTestSubject('synonyms-set-item-equivalent').text().trim(),
132+
};
133+
}
134+
})
135+
);
136+
},
137+
async clickCreateRuleButton() {
138+
await testSubjects.click(this.TEST_IDS.ADD_NEW_RULE_BUTTON);
139+
},
140+
async clickEquivalentRule() {
141+
await testSubjects.click(this.TEST_IDS.EMPTY_RULES_CARDS_ADD_EQUIVALENT_RULE_BUTTON);
142+
},
143+
async clickExplicitRule() {
144+
await testSubjects.click(this.TEST_IDS.EMPTY_RULES_CARDS_ADD_EXPLICIT_RULE_BUTTON);
145+
},
146+
async deleteRule(index: number) {
147+
const table = await testSubjects.find('synonyms-set-table');
148+
const allRows = await table
149+
.findByTagName('tbody')
150+
.then((tbody) => tbody.findAllByTagName('tr'));
151+
const deleteButton = await allRows[index].findByTestSubject(
152+
this.TEST_IDS.RULE_ACTIONS_DELETE_BUTTON
153+
);
154+
await deleteButton.click();
155+
await testSubjects.click('confirmModalConfirmButton');
156+
},
157+
async editRule(index: number) {
158+
const table = await testSubjects.find('synonyms-set-table');
159+
const allRows = await table
160+
.findByTagName('tbody')
161+
.then((tbody) => tbody.findAllByTagName('tr'));
162+
const editButton = await allRows[index].findByTestSubject(
163+
this.TEST_IDS.RULE_ACTIONS_EDIT_BUTTON
164+
);
165+
await editButton.click();
166+
},
167+
},
168+
SynonymRuleFlyout: {
169+
TEST_IDS: {
170+
FLYOUT_CLOSE_BUTTON: 'euiFlyoutCloseButton',
171+
FLYOUT_SAVE_BUTTON: 'searchSynonymsSynonymsRuleFlyoutSaveButton',
172+
FLYOUT_FROM_INPUT: 'searchSynonymsSynonymsRuleFlyoutFromTermsInput',
173+
FLYOUT_MAPTO_INPUT: 'searchSynonymsSynonymsRuleFlyoutMapToTermsInput',
174+
FLYOUT_FROM_BADGE: 'searchSynonymsSynonymsRuleFlyoutFromTermBadge',
175+
},
176+
async addFromSynonym(synonym: string) {
177+
await testSubjects.setValue(this.TEST_IDS.FLYOUT_FROM_INPUT, synonym);
178+
await testSubjects.setValue(this.TEST_IDS.FLYOUT_FROM_INPUT, '\uE007');
179+
},
180+
async addMapTo(synonym: string) {
181+
await testSubjects.setValue(this.TEST_IDS.FLYOUT_MAPTO_INPUT, synonym);
182+
},
183+
async clickSaveButton() {
184+
await testSubjects.click(this.TEST_IDS.FLYOUT_SAVE_BUTTON);
185+
},
186+
async removeSynonym(index: number) {
187+
// get the badges and click on the one with the index
188+
const badges = await testSubjects.findAll(this.TEST_IDS.FLYOUT_FROM_BADGE);
189+
if (index >= badges.length) {
190+
throw new Error(`Badge with index ${index} not found`);
191+
}
192+
const deleteButton = await badges[index].findByTagName('button');
193+
await deleteButton.click();
23194
},
24195
},
25196
};

x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
1111
describe('serverless search UI - feature flags', function () {
1212
// add tests that require feature flags, defined in config.feature_flags.ts
1313
loadTestFile(require.resolve('./search_synonyms/search_synonyms_overview'));
14+
loadTestFile(require.resolve('./search_synonyms/search_synonym_detail'));
1415
});
1516
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import expect from '@kbn/expect';
9+
import { FtrProviderContext } from '../../../ftr_provider_context';
10+
11+
export default function ({ getPageObjects, getService }: FtrProviderContext) {
12+
const pageObjects = getPageObjects([
13+
'svlCommonPage',
14+
'svlCommonNavigation',
15+
'searchSynonyms',
16+
'embeddedConsole',
17+
'common',
18+
]);
19+
const browser = getService('browser');
20+
const es = getService('es');
21+
const kibanaServer = getService('kibanaServer');
22+
23+
describe('Serverless Synonyms Set Detail', function () {
24+
before(async () => {
25+
await kibanaServer.uiSettings.update({ 'searchSynonyms:synonymsEnabled': 'true' });
26+
await pageObjects.svlCommonPage.loginWithRole('developer');
27+
});
28+
29+
describe('Synonyms Set Detail Page', () => {
30+
before(async () => {
31+
await es.transport.request({
32+
path: '_synonyms/test-synonym-details',
33+
method: 'PUT',
34+
body: {
35+
synonyms_set: [
36+
{
37+
id: 'rule1',
38+
synonyms: 'a,b,c',
39+
},
40+
{
41+
id: 'rule2',
42+
synonyms: 'd,e => f',
43+
},
44+
],
45+
},
46+
});
47+
});
48+
49+
it('loads successfully with rules', async () => {
50+
await pageObjects.common.navigateToApp('elasticsearch/synonyms/sets/test-synonym-details');
51+
52+
await pageObjects.searchSynonyms.SynonymsSetDetailPage.expectSynonymsSetDetailPageNavigated(
53+
'test-synonym-details'
54+
);
55+
// get the rules
56+
const rules = await pageObjects.searchSynonyms.SynonymsSetDetailPage.getSynonymsRules();
57+
expect(rules).to.eql([{ synonyms: 'a,b,c' }, { synonyms: 'd,e => f' }]);
58+
});
59+
60+
it('adds and deletes new equivalent rule', async () => {
61+
await pageObjects.common.navigateToApp('elasticsearch/synonyms/sets/test-synonym-details');
62+
63+
await pageObjects.searchSynonyms.SynonymsSetDetailPage.clickCreateRuleButton();
64+
await pageObjects.searchSynonyms.SynonymsSetDetailPage.clickEquivalentRule();
65+
await pageObjects.searchSynonyms.SynonymRuleFlyout.addFromSynonym('synonym1');
66+
await pageObjects.searchSynonyms.SynonymRuleFlyout.addFromSynonym('synonym2');
67+
await pageObjects.searchSynonyms.SynonymRuleFlyout.clickSaveButton();
68+
69+
await browser.refresh();
70+
71+
const rules = await pageObjects.searchSynonyms.SynonymsSetDetailPage.getSynonymsRules();
72+
expect(rules).to.eql([
73+
{ synonyms: 'synonym1,synonym2' },
74+
{ synonyms: 'a,b,c' },
75+
{ synonyms: 'd,e => f' },
76+
]);
77+
78+
// Delete new rule
79+
await pageObjects.searchSynonyms.SynonymsSetDetailPage.deleteRule(0);
80+
81+
await browser.refresh();
82+
const updatedRules =
83+
await pageObjects.searchSynonyms.SynonymsSetDetailPage.getSynonymsRules();
84+
expect(updatedRules).to.eql([{ synonyms: 'a,b,c' }, { synonyms: 'd,e => f' }]);
85+
});
86+
87+
it('adds and deletes new explicit rule', async () => {
88+
await pageObjects.common.navigateToApp('elasticsearch/synonyms/sets/test-synonym-details');
89+
await pageObjects.searchSynonyms.SynonymsSetDetailPage.clickCreateRuleButton();
90+
await pageObjects.searchSynonyms.SynonymsSetDetailPage.clickExplicitRule();
91+
await pageObjects.searchSynonyms.SynonymRuleFlyout.addFromSynonym('synonym1');
92+
await pageObjects.searchSynonyms.SynonymRuleFlyout.addFromSynonym('synonym2');
93+
await pageObjects.searchSynonyms.SynonymRuleFlyout.addMapTo('synonym3');
94+
await pageObjects.searchSynonyms.SynonymRuleFlyout.clickSaveButton();
95+
await browser.refresh();
96+
97+
const rules = await pageObjects.searchSynonyms.SynonymsSetDetailPage.getSynonymsRules();
98+
expect(rules).to.eql([
99+
{ synonyms: 'synonym1,synonym2 => synonym3' },
100+
{ synonyms: 'a,b,c' },
101+
{ synonyms: 'd,e => f' },
102+
]);
103+
// delete the new rule
104+
await pageObjects.searchSynonyms.SynonymsSetDetailPage.deleteRule(0);
105+
await browser.refresh();
106+
const updatedRules =
107+
await pageObjects.searchSynonyms.SynonymsSetDetailPage.getSynonymsRules();
108+
expect(updatedRules).to.eql([{ synonyms: 'a,b,c' }, { synonyms: 'd,e => f' }]);
109+
});
110+
111+
it('edits an existing rule', async () => {
112+
await pageObjects.common.navigateToApp('elasticsearch/synonyms/sets/test-synonym-details');
113+
// edit the first rule
114+
await pageObjects.searchSynonyms.SynonymsSetDetailPage.editRule(0);
115+
await pageObjects.searchSynonyms.SynonymRuleFlyout.removeSynonym(0);
116+
await pageObjects.searchSynonyms.SynonymRuleFlyout.addFromSynonym('synonym3');
117+
await pageObjects.searchSynonyms.SynonymRuleFlyout.clickSaveButton();
118+
await browser.refresh();
119+
const rules = await pageObjects.searchSynonyms.SynonymsSetDetailPage.getSynonymsRules();
120+
expect(rules).to.eql([{ synonyms: 'b,c,synonym3' }, { synonyms: 'd,e => f' }]);
121+
});
122+
123+
after(async () => {
124+
await es.transport.request({
125+
path: '_synonyms/test-synonym-details',
126+
method: 'DELETE',
127+
});
128+
});
129+
});
130+
});
131+
}

0 commit comments

Comments
 (0)