diff --git a/web/cypress/integration/route/create-route-with-advanced-matching-conditions.spec.js b/web/cypress/integration/route/create-route-with-advanced-matching-conditions.spec.js new file mode 100644 index 0000000000..5f7c7717ec --- /dev/null +++ b/web/cypress/integration/route/create-route-with-advanced-matching-conditions.spec.js @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* eslint-disable no-undef */ + +context('Create Route with advanced matching conditions', () => { + const selector = { + name: '#name', + nodes_0_host: '#nodes_0_host', + nodes_0_port: '#nodes_0_port', + nodes_0_weight: '#nodes_0_weight', + deleteAlert: '.ant-modal-body', + notificationCloseIcon: '.ant-notification-close-icon', + notification: '.ant-notification-notice-message', + parameterPosition: '#position', + ruleCard: '.ant-modal', + operator: '#operator', + value: '#value', + advancedMatchingTable: '.ant-table-row.ant-table-row-level-0', + advancedMatchingTableOperation: '.ant-space', + advancedMatchingTableCell: '.ant-table-cell', + }; + + const data = { + routeName: `test_route_${new Date().valueOf()}`, + submitSuccess: 'Submit Successfully', + ip1: '127.0.0.1', + port: '80', + weight: 1, + matchingParamName: 'server_port', + deleteRouteSuccess: 'Delete Route Successfully', + }; + + const opreatorList = [ + // 'Equal(==)' : '1234', + 'Unequal(~=)', + 'Greater Than(>)', + 'Less Than(<)', + // 'Regex Match(~~)', + 'IN', + ]; + + const matchingValueList1 = ['1000', '800', '2000', '["1800","1888"]']; + + const matchingValueList2 = ['2000', '1800', '3000', '["2800","2888"]']; + + beforeEach(() => { + cy.login(); + }); + + it('should create route with advanced matching conditions', function () { + cy.visit('/routes/list'); + cy.contains('Create').click(); + cy.contains('Next').click().click(); + cy.get(selector.name).type(data.routeName); + + // All Of Operational Character Should Exist And Can be Created + cy.wrap(opreatorList).each((opreator, index) => { + cy.contains('Advanced Routing Matching Conditions') + .parent() + .siblings() + .contains('Add') + .click() + .then(() => { + cy.get(selector.parameterPosition) + .click() + .then(() => { + cy.get('.ant-select-dropdown').within(() => { + cy.contains('Build-in').should('be.visible').click(); + }); + }); + cy.get(selector.ruleCard).within(() => { + cy.get(selector.name).type(data.matchingParamName); + }); + cy.get(selector.operator).click(); + cy.get(`[title="${opreator}"]`).should('be.visible').click(); + cy.get(selector.value).type(matchingValueList1[index]); + cy.contains('Confirm').click(); + }); + }); + cy.get(selector.advancedMatchingTable).should('exist'); + cy.wrap(opreatorList).each((operator, index) => { + cy.get(selector.advancedMatchingTableCell).within(() => { + cy.contains('td', 'Build-in Parameter').should('be.visible'); + cy.contains('td', data.matchingParamName).should('be.visible'); + cy.contains('td', matchingValueList1[index]).should('be.visible'); + }); + }); + cy.contains('Next').click(); + cy.get(selector.nodes_0_host).clear().type(data.ip1); + cy.get(selector.nodes_0_port).type(data.port); + cy.get(selector.nodes_0_weight).type(data.weight); + cy.contains('Next').click(); + cy.contains('Next').click(); + cy.contains('Submit').click(); + cy.contains(data.submitSuccess).should('be.visible'); + cy.contains('Goto List').click(); + cy.url().should('contains', 'routes/list'); + }); + + it('should edit this route matching conditions', function () { + cy.visit('/routes/list'); + cy.get(selector.name).clear().type(data.routeName); + cy.contains('Search').click(); + cy.contains(data.routeName).siblings().contains('Configure').click(); + cy.get(selector.advancedMatchingTable).should('exist'); + cy.wrap(opreatorList).each((opreator, index) => { + cy.get(selector.advancedMatchingTableCell).within(() => { + cy.contains(`${opreator}`) + .parent('tr') + .within(() => { + cy.get(selector.advancedMatchingTableOperation).within(() => { + cy.contains('Configure').click(); + }); + }); + }); + cy.get(selector.ruleCard).within(() => { + cy.get(`[title="Build-in Parameter"]`).should('have.class', 'ant-select-selection-item'); + cy.get(selector.name).clear().type(data.matchingParamName); + cy.get(`[title="${opreator}"]`).should('have.class', 'ant-select-selection-item'); + cy.get(selector.value).clear().type(matchingValueList2[index]); + cy.contains('Confirm').click(); + }); + cy.get(selector.advancedMatchingTableCell).within(() => { + cy.contains('td', 'Build-in Parameter').should('be.visible'); + cy.contains('td', data.matchingParamName).should('be.visible'); + cy.contains('td', matchingValueList2[index]).should('be.visible'); + }); + }); + cy.contains('Next').click(); + cy.get(selector.nodes_0_port).focus(); + cy.contains('Next').click(); + cy.contains('Next').click(); + cy.contains('Submit').click(); + cy.contains(data.submitSuccess); + cy.contains('Goto List').click(); + cy.url().should('contains', 'routes/list'); + }); + + it('should delete route matching conditions', function () { + cy.visit('/routes/list'); + cy.get(selector.name).clear().type(data.routeName); + cy.contains('Search').click(); + cy.contains(data.routeName).siblings().contains('Configure').click(); + cy.get(selector.name).should('value', data.routeName); + cy.get(selector.advancedMatchingTable).should('exist'); + cy.wrap(opreatorList).each(() => { + cy.get(selector.advancedMatchingTableOperation).within(() => { + cy.contains('Delete').click().should('not.exist'); + }); + }); + cy.get(selector.advancedMatchingTable).should('not.exist'); + cy.contains('Next').click(); + cy.get(selector.nodes_0_port).focus(); + cy.contains('Next').click(); + cy.contains('Next').click(); + cy.contains('Submit').click(); + cy.contains(data.submitSuccess); + cy.contains('Goto List').click(); + cy.url().should('contains', 'routes/list'); + + cy.visit('/routes/list'); + cy.get(selector.name).clear().type(data.routeName); + cy.contains('Search').click(); + cy.contains(data.routeName).siblings().contains('More').click(); + cy.contains('Delete').click(); + cy.get(selector.deleteAlert) + .should('be.visible') + .within(() => { + cy.contains('OK').click(); + }); + cy.get(selector.notification).should('contain', data.deleteRouteSuccess); + cy.get(selector.notificationCloseIcon).click(); + }); +}); diff --git a/web/src/pages/Route/components/Step1/MatchingRulesView.tsx b/web/src/pages/Route/components/Step1/MatchingRulesView.tsx index ad55b39863..ccbb97c511 100644 --- a/web/src/pages/Route/components/Step1/MatchingRulesView.tsx +++ b/web/src/pages/Route/components/Step1/MatchingRulesView.tsx @@ -116,6 +116,9 @@ const MatchingRulesView: React.FC = ({ case 'cookie': renderText = 'Cookie'; break; + case 'buildin': + renderText = formatMessage({ id: 'page.route.buildinParameter' }); + break; default: renderText = ''; } @@ -206,6 +209,7 @@ const MatchingRulesView: React.FC = ({ + data.map(([key, operator, value]) => { - const [, position, name] = key.split(/^(cookie|http|arg)_/); + let position = ''; + let name = ''; + const regex = new RegExp('^(cookie|http|arg)_.+'); + if (regex.test(key)) { + [, position, name] = key.split(/^(cookie|http|arg)_/); + }else { + position = "buildin"; + name = key; + } return { position: position as RouteModule.VarPosition, name, diff --git a/web/src/pages/Route/typing.d.ts b/web/src/pages/Route/typing.d.ts index 77bce06e58..4870e380e9 100644 --- a/web/src/pages/Route/typing.d.ts +++ b/web/src/pages/Route/typing.d.ts @@ -17,7 +17,7 @@ declare namespace RouteModule { type Operator = '==' | '~=' | '>' | '<' | '~~' | '~*' | 'IN' | 'HAS' | '!'; - type VarPosition = 'arg' | 'http' | 'cookie'; + type VarPosition = 'arg' | 'http' | 'cookie' | 'buildin'; type RequestProtocol = 'https' | 'http' | 'websocket';