Skip to content

Commit

Permalink
[Console] Add tests for XJSON (#136711)
Browse files Browse the repository at this point in the history
* [Console] Add tests for XJSON

* Convert rgb to hex

* Address CR changes

* Expand test coverage for XJSON

* Retry until typing is finished

Co-authored-by: Muhammad Ibragimov <[email protected]>
Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
3 people authored Oct 10, 2022
1 parent 1da866e commit dfede09
Show file tree
Hide file tree
Showing 2 changed files with 248 additions and 11 deletions.
158 changes: 147 additions & 11 deletions test/functional/apps/console/_xjson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@
*/

import expect from '@kbn/expect';
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');
await PageObjects.common.navigateToApp('console');
await retry.try(async () => {
await PageObjects.console.collapseHelp();
Expand All @@ -28,22 +28,158 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => {
await PageObjects.console.clearTextArea();
});

describe('with triple quoted strings', () => {
const executeRequest = async (request = '\n GET _search') => {
await PageObjects.console.enterRequest(request);
await PageObjects.console.clickPlay();
await PageObjects.header.waitUntilLoadingHasFinished();
};

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 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 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 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');
});

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": {}}}'
);
// 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 () => {
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);
});
});

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();
// 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 () => {
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 () => {
await executeRequest('\n GET _search // inline comment');
expect(await PageObjects.console.hasErrorMarker()).to.be(false);
expect(await PageObjects.console.getResponseStatus()).to.eql(200);
});

it('should allow inline comments in request body', async () => {
await executeRequest('\n GET _search \n{\n "query": {\n "match_all": {} // inline comment');
expect(await PageObjects.console.hasErrorMarker()).to.be(false);
expect(await PageObjects.console.getResponseStatus()).to.eql(200);
});

it('should print warning for deprecated request', async () => {
await executeRequest('\nGET .kibana');
expect(await PageObjects.console.responseHasDeprecationWarning()).to.be(true);
});
});

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);
it('should not print warning for non-deprecated request', async () => {
await executeRequest('\n GET _search');
expect(await PageObjects.console.responseHasDeprecationWarning()).to.be(false);
});
});
});
Expand Down
101 changes: 101 additions & 0 deletions test/functional/page_objects/console_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,19 @@ 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() {
// 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() {
const widget = await this.find.byCssSelector('.ace_fold-widget');
await widget.click();
Expand Down Expand Up @@ -404,4 +417,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;
}
}

0 comments on commit dfede09

Please sign in to comment.