From 1560fbdd8fe1b555294a946162a20cc11eb83fbc Mon Sep 17 00:00:00 2001 From: Muhammad Ibragimov Date: Wed, 20 Jul 2022 14:27:56 +0500 Subject: [PATCH 1/8] [Console] Add tests for XJSON --- test/functional/apps/console/_xjson.ts | 100 +++++++++++++++++++ test/functional/page_objects/console_page.ts | 10 ++ 2 files changed, 110 insertions(+) diff --git a/test/functional/apps/console/_xjson.ts b/test/functional/apps/console/_xjson.ts index 386cda8ef32ea..9f91f6d30c8de 100644 --- a/test/functional/apps/console/_xjson.ts +++ b/test/functional/apps/console/_xjson.ts @@ -28,6 +28,60 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { await PageObjects.console.clearTextArea(); }); + describe('with inline http requests', () => { + it('should issue a successful request', async () => { + await PageObjects.console.enterRequest(); + await PageObjects.console.clickPlay(); + await PageObjects.header.waitUntilLoadingHasFinished(); + const status = await PageObjects.console.getResponseStatus(); + expect(parseInt(status, 10)).to.be(200); + }); + + it('should be correctly syntax highlighted', async () => { + const methodTokenComputedColor = 'rgba(200, 10, 104, 1)'; + const urlTokenComputedColor = 'rgba(0, 117, 108, 1)'; + await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": "bar"'); + const methodTokenColor = await PageObjects.console.getTokenColor('ace_method'); + const urlColor = await PageObjects.console.getTokenColor('ace_url'); + expect(methodTokenColor).to.eql(methodTokenComputedColor); + expect(urlColor).to.eql(urlTokenComputedColor); + }); + + describe('with valid request', () => { + it('should not trigger validation errors', async () => { + await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": "bar"'); + expect(await PageObjects.console.hasInvalidSyntax()).to.be(false); + expect(await PageObjects.console.hasErrorMarker()).to.be(false); + }); + }); + + describe('with invalid request', () => { + it('should trigger validation errors', async () => { + await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": \'\''); + expect(await PageObjects.console.hasInvalidSyntax()).to.be(true); + expect(await PageObjects.console.hasErrorMarker()).to.be(true); + }); + }); + }); + + describe('with multiple bodies for msearch requests', () => { + it('should not trigger validation errors', async () => { + await PageObjects.console.enterRequest( + '\nGET foo/_msearch \n{}\n{"query": {"match_all": {}}}\n{"index": "bar"}\n{"query": {"match_all": {}}}' + ); + expect(await PageObjects.console.hasErrorMarker()).to.be(false); + }); + }); + + describe('with multiple JSON blocks', () => { + it('should not trigger validation errors', async () => { + await PageObjects.console.enterRequest('\nPOST test/doc/1 \n{\n "foo": "bar"'); + await PageObjects.console.enterRequest('\nPOST test/doc/1 \n{\n "foo": "bar"'); + await PageObjects.console.enterRequest('\nPOST test/doc/1 \n{\n "foo": "bar"'); + expect(await PageObjects.console.hasErrorMarker()).to.be(false); + }); + }); + describe('with triple quoted strings', () => { it('should allow escaping quotation mark by wrapping it in triple quotes', async () => { await PageObjects.console.enterRequest( @@ -44,6 +98,52 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": \'\''); expect(await PageObjects.console.hasInvalidSyntax()).to.be(true); expect(await PageObjects.console.hasErrorMarker()).to.be(true); + expect(await PageObjects.console.hasErrorMarker()).to.be(false); + }); + }); + + describe('with inline comments', () => { + it('should be correctly syntax highlighted', async () => { + const commentTokenComputedColor = 'rgba(65, 117, 92, 1)'; + await PageObjects.console.enterRequest('\n GET _search // inline comment'); + const color = await PageObjects.console.getTokenColor('ace_comment'); + expect(color).to.eql(commentTokenComputedColor); + }); + + it('should allow inline comments in request url row', async () => { + await PageObjects.console.enterRequest('\n GET _search // inline comment'); + expect(await PageObjects.console.hasErrorMarker()).to.be(false); + await PageObjects.console.clickPlay(); + await PageObjects.header.waitUntilLoadingHasFinished(); + expect(await PageObjects.console.getResponseStatus()).to.eql(200); + }); + + it('should allow inline comments in request body', async () => { + await PageObjects.console.enterRequest( + '\n GET _search \n{\n "query": {\n "match_all": {} // inline comment' + ); + expect(await PageObjects.console.hasErrorMarker()).to.be(false); + await PageObjects.console.clickPlay(); + await PageObjects.header.waitUntilLoadingHasFinished(); + expect(await PageObjects.console.getResponseStatus()).to.eql(200); + }); + }); + + describe('with a request using a deprecated feature', () => { + it('should print a warning into the response pane above the JSON', async () => { + await PageObjects.console.enterRequest('\nGET .kibana'); + await PageObjects.console.clickPlay(); + await PageObjects.header.waitUntilLoadingHasFinished(); + expect(await PageObjects.console.responseHasDeprecationWarning()).to.be(true); + }); + }); + + describe('with a request using no deprecated feature', () => { + it('should not print a warning into the response pane', async () => { + await PageObjects.console.enterRequest(); + await PageObjects.console.clickPlay(); + await PageObjects.header.waitUntilLoadingHasFinished(); + expect(await PageObjects.console.responseHasDeprecationWarning()).to.be(false); }); }); }); diff --git a/test/functional/page_objects/console_page.ts b/test/functional/page_objects/console_page.ts index 9f662a09146e9..c6fb001c3bf05 100644 --- a/test/functional/page_objects/console_page.ts +++ b/test/functional/page_objects/console_page.ts @@ -227,6 +227,16 @@ export class ConsolePageObject extends FtrService { return await this.find.existsByCssSelector('.ace_error'); } + public async getTokenColor(token: string) { + const element = await this.find.byClassName(token); + return await element.getComputedStyle('color'); + } + + public async responseHasDeprecationWarning() { + const response = await this.getResponse(); + return response.trim().startsWith('#!'); + } + public async clickFoldWidget() { const widget = await this.find.byCssSelector('.ace_fold-widget'); await widget.click(); From 5bdafbcea5e3d252c67d28a21fde5b38b2b8a1f3 Mon Sep 17 00:00:00 2001 From: Muhammad Ibragimov Date: Wed, 20 Jul 2022 16:16:46 +0500 Subject: [PATCH 2/8] Convert rgb to hex --- test/functional/apps/console/_xjson.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/test/functional/apps/console/_xjson.ts b/test/functional/apps/console/_xjson.ts index 9f91f6d30c8de..5474818364c45 100644 --- a/test/functional/apps/console/_xjson.ts +++ b/test/functional/apps/console/_xjson.ts @@ -8,6 +8,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; +import { rgbToHex } from '@elastic/eui'; export default ({ getService, getPageObjects }: FtrProviderContext) => { const retry = getService('retry'); @@ -38,13 +39,14 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { }); it('should be correctly syntax highlighted', async () => { - const methodTokenComputedColor = 'rgba(200, 10, 104, 1)'; - const urlTokenComputedColor = 'rgba(0, 117, 108, 1)'; + const methodTokenColor = '#c80a68'; + const urlTokenColor = '#00756c'; await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": "bar"'); - const methodTokenColor = await PageObjects.console.getTokenColor('ace_method'); - const urlColor = await PageObjects.console.getTokenColor('ace_url'); - expect(methodTokenColor).to.eql(methodTokenComputedColor); - expect(urlColor).to.eql(urlTokenComputedColor); + const methodTokenColorRGB = await PageObjects.console.getTokenColor('ace_method'); + const urlColorRGB = await PageObjects.console.getTokenColor('ace_url'); + // getTokenColor returns rgb value of css color property, we need to convert rgb to hex to compare it to the actual value + expect(rgbToHex(methodTokenColorRGB)).to.eql(methodTokenColor); + expect(rgbToHex(urlColorRGB)).to.eql(urlTokenColor); }); describe('with valid request', () => { @@ -104,10 +106,10 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { describe('with inline comments', () => { it('should be correctly syntax highlighted', async () => { - const commentTokenComputedColor = 'rgba(65, 117, 92, 1)'; + const commentTokenColor = '#41755c'; await PageObjects.console.enterRequest('\n GET _search // inline comment'); - const color = await PageObjects.console.getTokenColor('ace_comment'); - expect(color).to.eql(commentTokenComputedColor); + const commentTokenColorRGB = await PageObjects.console.getTokenColor('ace_comment'); + expect(rgbToHex(commentTokenColorRGB)).to.eql(commentTokenColor); }); it('should allow inline comments in request url row', async () => { From 5638345b0f0ff27aaf36936e115c6cc4eab80892 Mon Sep 17 00:00:00 2001 From: Muhammad Ibragimov Date: Mon, 8 Aug 2022 10:39:13 +0500 Subject: [PATCH 3/8] Refactor --- test/functional/apps/console/_xjson.ts | 61 ++++++++++---------------- 1 file changed, 23 insertions(+), 38 deletions(-) diff --git a/test/functional/apps/console/_xjson.ts b/test/functional/apps/console/_xjson.ts index 5474818364c45..1676a109ce5ec 100644 --- a/test/functional/apps/console/_xjson.ts +++ b/test/functional/apps/console/_xjson.ts @@ -7,15 +7,15 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; import { rgbToHex } from '@elastic/eui'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ getService, getPageObjects }: FtrProviderContext) => { const retry = getService('retry'); const log = getService('log'); const PageObjects = getPageObjects(['common', 'console', 'header']); - describe("Console's XJSON features", function testXjson() { + describe('XJSON', function testXjson() { this.tags('includeFirefox'); before(async () => { log.debug('navigateTo console'); @@ -29,13 +29,22 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { await PageObjects.console.clearTextArea(); }); - describe('with inline http requests', () => { - it('should issue a successful request', async () => { - await PageObjects.console.enterRequest(); - await PageObjects.console.clickPlay(); - await PageObjects.header.waitUntilLoadingHasFinished(); - const status = await PageObjects.console.getResponseStatus(); - expect(parseInt(status, 10)).to.be(200); + describe('inline HTTP requests', () => { + it('should not trigger validation errors with a valid request', async () => { + await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": "bar"'); + expect(await PageObjects.console.hasInvalidSyntax()).to.be(false); + expect(await PageObjects.console.hasErrorMarker()).to.be(false); + }); + + it('should trigger validation errors with an invalid request', async () => { + await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": \'\''); + expect(await PageObjects.console.hasInvalidSyntax()).to.be(true); + expect(await PageObjects.console.hasErrorMarker()).to.be(true); + }); + + it('should trigger validation errors with an invalid syntax', async () => { + await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": \'\''); + expect(await PageObjects.console.hasInvalidSyntax()).to.be(true); }); it('should be correctly syntax highlighted', async () => { @@ -48,25 +57,9 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { expect(rgbToHex(methodTokenColorRGB)).to.eql(methodTokenColor); expect(rgbToHex(urlColorRGB)).to.eql(urlTokenColor); }); - - describe('with valid request', () => { - it('should not trigger validation errors', async () => { - await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": "bar"'); - expect(await PageObjects.console.hasInvalidSyntax()).to.be(false); - expect(await PageObjects.console.hasErrorMarker()).to.be(false); - }); - }); - - describe('with invalid request', () => { - it('should trigger validation errors', async () => { - await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": \'\''); - expect(await PageObjects.console.hasInvalidSyntax()).to.be(true); - expect(await PageObjects.console.hasErrorMarker()).to.be(true); - }); - }); }); - describe('with multiple bodies for msearch requests', () => { + describe('multiple bodies for msearch requests', () => { it('should not trigger validation errors', async () => { await PageObjects.console.enterRequest( '\nGET foo/_msearch \n{}\n{"query": {"match_all": {}}}\n{"index": "bar"}\n{"query": {"match_all": {}}}' @@ -75,7 +68,7 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { }); }); - describe('with multiple JSON blocks', () => { + describe('multiple JSON blocks', () => { it('should not trigger validation errors', async () => { await PageObjects.console.enterRequest('\nPOST test/doc/1 \n{\n "foo": "bar"'); await PageObjects.console.enterRequest('\nPOST test/doc/1 \n{\n "foo": "bar"'); @@ -84,7 +77,7 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { }); }); - describe('with triple quoted strings', () => { + describe('triple quoted strings', () => { it('should allow escaping quotation mark by wrapping it in triple quotes', async () => { await PageObjects.console.enterRequest( '\nPOST test/_doc/1 \n{\n "foo": """look "escaped" quotes"""' @@ -95,20 +88,12 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { }); }); - describe('with invalid syntax', () => { - it('should trigger validation errors', async () => { - await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": \'\''); - expect(await PageObjects.console.hasInvalidSyntax()).to.be(true); - expect(await PageObjects.console.hasErrorMarker()).to.be(true); - expect(await PageObjects.console.hasErrorMarker()).to.be(false); - }); - }); - - describe('with inline comments', () => { + describe('inline comments', () => { it('should be correctly syntax highlighted', async () => { const commentTokenColor = '#41755c'; await PageObjects.console.enterRequest('\n GET _search // inline comment'); const commentTokenColorRGB = await PageObjects.console.getTokenColor('ace_comment'); + // getTokenColor returns rgb value of css color property, we need to convert rgb to hex to compare it to the actual value expect(rgbToHex(commentTokenColorRGB)).to.eql(commentTokenColor); }); From 618f0c248588ec40f56639f74ef9d921fa332152 Mon Sep 17 00:00:00 2001 From: Muhammad Ibragimov Date: Tue, 23 Aug 2022 15:03:39 +0500 Subject: [PATCH 4/8] Address CR changes --- test/functional/apps/console/_xjson.ts | 30 ++++++++++---------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/test/functional/apps/console/_xjson.ts b/test/functional/apps/console/_xjson.ts index 1676a109ce5ec..da3ac6dd2268b 100644 --- a/test/functional/apps/console/_xjson.ts +++ b/test/functional/apps/console/_xjson.ts @@ -29,6 +29,12 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { await PageObjects.console.clearTextArea(); }); + const executeRequest = async (request = '\n GET _search') => { + await PageObjects.console.enterRequest(request); + await PageObjects.console.clickPlay(); + await PageObjects.header.waitUntilLoadingHasFinished(); + }; + describe('inline HTTP requests', () => { it('should not trigger validation errors with a valid request', async () => { await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": "bar"'); @@ -79,11 +85,7 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { describe('triple quoted strings', () => { it('should allow escaping quotation mark by wrapping it in triple quotes', async () => { - await PageObjects.console.enterRequest( - '\nPOST test/_doc/1 \n{\n "foo": """look "escaped" quotes"""' - ); - await PageObjects.console.clickPlay(); - await PageObjects.header.waitUntilLoadingHasFinished(); + await executeRequest('\nPOST test/_doc/1 \n{\n "foo": """look "escaped" quotes"""'); expect(await PageObjects.console.hasErrorMarker()).to.be(false); }); }); @@ -98,38 +100,28 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { }); it('should allow inline comments in request url row', async () => { - await PageObjects.console.enterRequest('\n GET _search // inline comment'); + await executeRequest('\n GET _search // inline comment'); expect(await PageObjects.console.hasErrorMarker()).to.be(false); - await PageObjects.console.clickPlay(); - await PageObjects.header.waitUntilLoadingHasFinished(); expect(await PageObjects.console.getResponseStatus()).to.eql(200); }); it('should allow inline comments in request body', async () => { - await PageObjects.console.enterRequest( - '\n GET _search \n{\n "query": {\n "match_all": {} // inline comment' - ); + await executeRequest('\n GET _search \n{\n "query": {\n "match_all": {} // inline comment'); expect(await PageObjects.console.hasErrorMarker()).to.be(false); - await PageObjects.console.clickPlay(); - await PageObjects.header.waitUntilLoadingHasFinished(); expect(await PageObjects.console.getResponseStatus()).to.eql(200); }); }); describe('with a request using a deprecated feature', () => { it('should print a warning into the response pane above the JSON', async () => { - await PageObjects.console.enterRequest('\nGET .kibana'); - await PageObjects.console.clickPlay(); - await PageObjects.header.waitUntilLoadingHasFinished(); + await executeRequest('\nGET .kibana'); expect(await PageObjects.console.responseHasDeprecationWarning()).to.be(true); }); }); describe('with a request using no deprecated feature', () => { it('should not print a warning into the response pane', async () => { - await PageObjects.console.enterRequest(); - await PageObjects.console.clickPlay(); - await PageObjects.header.waitUntilLoadingHasFinished(); + await executeRequest(); expect(await PageObjects.console.responseHasDeprecationWarning()).to.be(false); }); }); From 7b7f3bdfe448c9540c36e6b571196aac28ee6f4f Mon Sep 17 00:00:00 2001 From: Muhammad Ibragimov Date: Wed, 31 Aug 2022 15:15:01 +0500 Subject: [PATCH 5/8] Fix flaky test failing on multiple json blocks --- test/functional/apps/console/_xjson.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/functional/apps/console/_xjson.ts b/test/functional/apps/console/_xjson.ts index da3ac6dd2268b..89459bba6d73e 100644 --- a/test/functional/apps/console/_xjson.ts +++ b/test/functional/apps/console/_xjson.ts @@ -67,7 +67,7 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { describe('multiple bodies for msearch requests', () => { it('should not trigger validation errors', async () => { - await PageObjects.console.enterRequest( + await executeRequest( '\nGET foo/_msearch \n{}\n{"query": {"match_all": {}}}\n{"index": "bar"}\n{"query": {"match_all": {}}}' ); expect(await PageObjects.console.hasErrorMarker()).to.be(false); @@ -76,9 +76,9 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { describe('multiple JSON blocks', () => { it('should not trigger validation errors', async () => { - await PageObjects.console.enterRequest('\nPOST test/doc/1 \n{\n "foo": "bar"'); - await PageObjects.console.enterRequest('\nPOST test/doc/1 \n{\n "foo": "bar"'); - await PageObjects.console.enterRequest('\nPOST test/doc/1 \n{\n "foo": "bar"'); + await executeRequest('\nPOST test/doc/1 \n{\n "foo": "bar"'); + await executeRequest('\nPOST test/doc/2 \n{\n "foo": "baz"'); + await executeRequest('\nPOST test/doc/3 \n{\n "foo": "qux"'); expect(await PageObjects.console.hasErrorMarker()).to.be(false); }); }); From 4208f7cb81314279b80e7d025cc529e89ffb753b Mon Sep 17 00:00:00 2001 From: Muhammad Ibragimov Date: Fri, 23 Sep 2022 15:22:11 +0500 Subject: [PATCH 6/8] Expand test coverage for XJSON --- test/functional/apps/console/_xjson.ts | 153 ++++++++++++------- test/functional/page_objects/console_page.ts | 88 +++++++++++ 2 files changed, 190 insertions(+), 51 deletions(-) diff --git a/test/functional/apps/console/_xjson.ts b/test/functional/apps/console/_xjson.ts index 89459bba6d73e..4729b1ed14e22 100644 --- a/test/functional/apps/console/_xjson.ts +++ b/test/functional/apps/console/_xjson.ts @@ -18,7 +18,6 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { describe('XJSON', function testXjson() { this.tags('includeFirefox'); before(async () => { - log.debug('navigateTo console'); await PageObjects.common.navigateToApp('console'); await retry.try(async () => { await PageObjects.console.collapseHelp(); @@ -35,68 +34,124 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { await PageObjects.header.waitUntilLoadingHasFinished(); }; - describe('inline HTTP requests', () => { - it('should not trigger validation errors with a valid request', async () => { - await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": "bar"'); - expect(await PageObjects.console.hasInvalidSyntax()).to.be(false); + describe('inline http request', () => { + it('should have method and path', async () => { + await PageObjects.console.enterRequest('\n PUT foo/bar'); + expect(await PageObjects.console.getRequestMethod()).to.be('PUT'); + expect(await PageObjects.console.getRequestPath()).to.be('foo/bar'); + }); + + it('should have optional query parameters', async () => { + await PageObjects.console.enterRequest('\n GET foo/bar?pretty'); + expect(await PageObjects.console.getRequestQueryParams()).to.be('pretty'); + }); + + it('should have optional request body', async () => { + await PageObjects.console.enterRequest('\n POST foo/bar\n {"foo": "bar"}'); + log.debug('request body: ' + (await PageObjects.console.getRequestBody())); + expect(await PageObjects.console.getRequestBody()).to.be('{"foo": "bar"}'); + }); + + it('should not have validation errors', async () => { + await PageObjects.console.enterRequest('\n GET foo/bar'); expect(await PageObjects.console.hasErrorMarker()).to.be(false); }); - it('should trigger validation errors with an invalid request', async () => { - await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": \'\''); - expect(await PageObjects.console.hasInvalidSyntax()).to.be(true); - expect(await PageObjects.console.hasErrorMarker()).to.be(true); + it('should have validation error for invalid method', async () => { + await PageObjects.console.enterRequest('\n FOO foo/bar'); + // Retry because the error marker is not always immediately visible. + await retry.try(async () => { + expect(await PageObjects.console.hasErrorMarker()).to.be(true); + }); }); - it('should trigger validation errors with an invalid syntax', async () => { - await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": \'\''); - expect(await PageObjects.console.hasInvalidSyntax()).to.be(true); + it('should have validation error for invalid path', async () => { + await PageObjects.console.enterRequest('\n GET'); + // Retry because the error marker is not always immediately visible. + await retry.try(async () => { + expect(await PageObjects.console.hasErrorMarker()).to.be(true); + }); }); - it('should be correctly syntax highlighted', async () => { - const methodTokenColor = '#c80a68'; - const urlTokenColor = '#00756c'; - await PageObjects.console.enterRequest('\nGET test/doc/1 \n{\n "foo": "bar"'); - const methodTokenColorRGB = await PageObjects.console.getTokenColor('ace_method'); - const urlColorRGB = await PageObjects.console.getTokenColor('ace_url'); - // getTokenColor returns rgb value of css color property, we need to convert rgb to hex to compare it to the actual value - expect(rgbToHex(methodTokenColorRGB)).to.eql(methodTokenColor); - expect(rgbToHex(urlColorRGB)).to.eql(urlTokenColor); + it('should have validation error for invalid body', async () => { + await PageObjects.console.enterRequest('\n POST foo/bar\n {"foo": "bar"'); + // Retry because the error marker is not always immediately visible. + await retry.try(async () => { + expect(await PageObjects.console.hasErrorMarker()).to.be(true); + }); + }); + + it('should have correct syntax highlighting', async () => { + await PageObjects.console.enterRequest('\n GET foo/bar'); + expect(await PageObjects.console.getRequestLineHighlighting()).to.contain( + 'ace_method ace_whitespace ace_url ace_part ace_url ace_slash ace_url ace_part' + ); + }); + + it('should have correct syntax highlighting for method', async () => { + await PageObjects.console.enterRequest('\n PUT foo/bar'); + const color = await PageObjects.console.getRequestMethodColor(); + expect(rgbToHex(color)).to.be('#c80a68'); + }); + + it('should have correct syntax highlighting for path', async () => { + await PageObjects.console.enterRequest('\n PUT foo/bar'); + const color = await PageObjects.console.getRequestPathColor(); + expect(rgbToHex(color)).to.be('#00756c'); + }); + + it('should have correct syntax highlighting for query', async () => { + await PageObjects.console.enterRequest('\n PUT foo/bar?pretty'); + const color = await PageObjects.console.getRequestQueryColor(); + expect(rgbToHex(color)).to.be('#00756c'); }); - }); - describe('multiple bodies for msearch requests', () => { - it('should not trigger validation errors', async () => { - await executeRequest( + it('should have correct syntax highlighting for body', async () => { + await PageObjects.console.enterRequest('\n PUT foo/bar\n {"foo": "bar"}'); + const color = await PageObjects.console.getRequestBodyColor(); + expect(rgbToHex(color)).to.be('#343741'); + }); + + it('should have multiple bodies for _msearch requests', async () => { + await PageObjects.console.enterRequest( '\nGET foo/_msearch \n{}\n{"query": {"match_all": {}}}\n{"index": "bar"}\n{"query": {"match_all": {}}}' ); - expect(await PageObjects.console.hasErrorMarker()).to.be(false); + expect(await PageObjects.console.getRequestBodyCount()).to.be(4); }); - }); - describe('multiple JSON blocks', () => { - it('should not trigger validation errors', async () => { - await executeRequest('\nPOST test/doc/1 \n{\n "foo": "bar"'); - await executeRequest('\nPOST test/doc/2 \n{\n "foo": "baz"'); - await executeRequest('\nPOST test/doc/3 \n{\n "foo": "qux"'); - expect(await PageObjects.console.hasErrorMarker()).to.be(false); + it('should not trigger error for multiple bodies for _msearch requests', async () => { + await PageObjects.console.enterRequest( + '\nGET foo/_msearch \n{}\n{"query": {"match_all": {}}}\n{"index": "bar"}\n{"query": {"match_all": {}}}' + ); + // Retry until typing is finished. + await retry.try(async () => { + expect(await PageObjects.console.hasErrorMarker()).to.be(false); + }); + }); + + it('should not trigger validation errors for multiple JSON blocks', async () => { + await PageObjects.console.enterRequest('\nPOST test/doc/1 \n{\n "foo": "bar"'); + await PageObjects.console.enterRequest('\nPOST test/doc/2 \n{\n "foo": "baz"'); + await PageObjects.console.enterRequest('\nPOST test/doc/3 \n{\n "foo": "qux"'); + // Retry until typing is finished. + await retry.try(async () => { + expect(await PageObjects.console.hasErrorMarker()).to.be(false); + }); }); - }); - describe('triple quoted strings', () => { it('should allow escaping quotation mark by wrapping it in triple quotes', async () => { - await executeRequest('\nPOST test/_doc/1 \n{\n "foo": """look "escaped" quotes"""'); + await PageObjects.console.enterRequest( + '\nPOST test/_doc/1 \n{\n "foo": """look "escaped" quotes"""' + ); expect(await PageObjects.console.hasErrorMarker()).to.be(false); }); - }); - describe('inline comments', () => { - it('should be correctly syntax highlighted', async () => { - const commentTokenColor = '#41755c'; - await PageObjects.console.enterRequest('\n GET _search // inline comment'); - const commentTokenColorRGB = await PageObjects.console.getTokenColor('ace_comment'); - // getTokenColor returns rgb value of css color property, we need to convert rgb to hex to compare it to the actual value - expect(rgbToHex(commentTokenColorRGB)).to.eql(commentTokenColor); + it('should have correct syntax highlighting for inline comments', async () => { + await PageObjects.console.enterRequest( + '\nPOST test/_doc/1 \n{\n "foo": "bar" # inline comment' + ); + const color = await PageObjects.console.getCommentColor(); + expect(rgbToHex(color)).to.be('#41755c'); }); it('should allow inline comments in request url row', async () => { @@ -110,18 +165,14 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { expect(await PageObjects.console.hasErrorMarker()).to.be(false); expect(await PageObjects.console.getResponseStatus()).to.eql(200); }); - }); - describe('with a request using a deprecated feature', () => { - it('should print a warning into the response pane above the JSON', async () => { + it('should print warning for deprecated request', async () => { await executeRequest('\nGET .kibana'); expect(await PageObjects.console.responseHasDeprecationWarning()).to.be(true); }); - }); - describe('with a request using no deprecated feature', () => { - it('should not print a warning into the response pane', async () => { - await executeRequest(); + it('should not print warning for non-deprecated request', async () => { + await executeRequest('\n GET _search'); expect(await PageObjects.console.responseHasDeprecationWarning()).to.be(false); }); }); diff --git a/test/functional/page_objects/console_page.ts b/test/functional/page_objects/console_page.ts index c6fb001c3bf05..749ed49325f04 100644 --- a/test/functional/page_objects/console_page.ts +++ b/test/functional/page_objects/console_page.ts @@ -414,4 +414,92 @@ export class ConsolePageObject extends FtrService { const button = await this.testSubjects.find('consoleMenuAutoIndent'); await button.click(); } + + public async getRequestMethod() { + const requestEditor = await this.getRequestEditor(); + const requestMethod = await requestEditor.findByClassName('ace_method'); + const method = await requestMethod.getVisibleText(); + return method.trim(); + } + + public async getRequestPath() { + const requestEditor = await this.getRequestEditor(); + const requestPath = await requestEditor.findAllByCssSelector('.ace_url'); + const path = []; + for (const pathPart of requestPath) { + const className = await pathPart.getAttribute('class'); + if (className.includes('ace_param')) { + // This is a parameter, we don't want to include it in the path + break; + } + path.push(await pathPart.getVisibleText()); + } + return path.join('').trim(); + } + + public async getRequestQueryParams() { + const requestEditor = await this.getRequestEditor(); + const requestQueryParams = await requestEditor.findAllByCssSelector('.ace_url.ace_param'); + + if (requestQueryParams.length === 0) { + // No query params + return; + } + + const params = []; + for (const param of requestQueryParams) { + params.push(await param.getVisibleText()); + } + return params.join('').trim(); + } + + public async getRequestBody() { + let request = await this.getRequest(); + // Remove new lines at the beginning of the request + request = request.replace(/^\n/, ''); + const method = await this.getRequestMethod(); + const path = await this.getRequestPath(); + const query = await this.getRequestQueryParams(); + + if (query) { + return request.replace(`${method} ${path}?${query}`, '').trim(); + } + + return request.replace(`${method} ${path}`, '').trim(); + } + + public async getRequestLineHighlighting() { + const requestEditor = await this.getRequestEditor(); + const requestLine = await requestEditor.findAllByCssSelector('.ace_line > *'); + const line = []; + for (const linePart of requestLine) { + line.push(await linePart.getAttribute('class')); + } + return line.join(' '); + } + + public async getRequestMethodColor() { + return await this.getTokenColor('ace_method'); + } + + public async getRequestPathColor() { + return await this.getTokenColor('ace_url'); + } + + public async getRequestQueryColor() { + return await this.getTokenColor('ace_param'); + } + + public async getRequestBodyColor() { + return await this.getTokenColor('ace_paren'); + } + + public async getCommentColor() { + return await this.getTokenColor('ace_comment'); + } + + public async getRequestBodyCount() { + const body = await this.getRequestBody(); + return body.split('\n').length; + } } From f3d2d8a77e875c711b64d829eb425b96826bb093 Mon Sep 17 00:00:00 2001 From: Muhammad Ibragimov Date: Mon, 26 Sep 2022 14:35:57 +0500 Subject: [PATCH 7/8] Rebase --- test/functional/page_objects/console_page.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/functional/page_objects/console_page.ts b/test/functional/page_objects/console_page.ts index 749ed49325f04..0069682f828d6 100644 --- a/test/functional/page_objects/console_page.ts +++ b/test/functional/page_objects/console_page.ts @@ -233,8 +233,11 @@ export class ConsolePageObject extends FtrService { } public async responseHasDeprecationWarning() { - const response = await this.getResponse(); - return response.trim().startsWith('#!'); + // Retry for a while to allow the deprecation warning to appear + return await this.retry.try(async () => { + const response = await this.getResponse(); + return response.trim().startsWith('#!'); + }); } public async clickFoldWidget() { From d5441c4739093938cf72cb1bde043cd89fdf7a5d Mon Sep 17 00:00:00 2001 From: Muhammad Ibragimov Date: Mon, 26 Sep 2022 17:46:08 +0500 Subject: [PATCH 8/8] Retry until typing is finished --- test/functional/apps/console/_xjson.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/functional/apps/console/_xjson.ts b/test/functional/apps/console/_xjson.ts index 4729b1ed14e22..1535337a2a848 100644 --- a/test/functional/apps/console/_xjson.ts +++ b/test/functional/apps/console/_xjson.ts @@ -116,7 +116,10 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { await PageObjects.console.enterRequest( '\nGET foo/_msearch \n{}\n{"query": {"match_all": {}}}\n{"index": "bar"}\n{"query": {"match_all": {}}}' ); - expect(await PageObjects.console.getRequestBodyCount()).to.be(4); + // Retry because body elements are not always immediately visible. + await retry.try(async () => { + expect(await PageObjects.console.getRequestBodyCount()).to.be(4); + }); }); it('should not trigger error for multiple bodies for _msearch requests', async () => { @@ -143,7 +146,10 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { await PageObjects.console.enterRequest( '\nPOST test/_doc/1 \n{\n "foo": """look "escaped" quotes"""' ); - expect(await PageObjects.console.hasErrorMarker()).to.be(false); + // Retry until typing is finished and validation errors are gone. + await retry.try(async () => { + expect(await PageObjects.console.hasErrorMarker()).to.be(false); + }); }); it('should have correct syntax highlighting for inline comments', async () => {