diff --git a/examples/response_stream/public/components/page.tsx b/examples/response_stream/public/components/page.tsx index e3138fafa71ab0..2626eb317cf17f 100644 --- a/examples/response_stream/public/components/page.tsx +++ b/examples/response_stream/public/components/page.tsx @@ -18,7 +18,7 @@ export const Page: FC> = ({ title = 'Untitled', chi <> -

{title}

+

{title}

{children} diff --git a/examples/response_stream/public/containers/app/pages/page_reducer_stream/index.tsx b/examples/response_stream/public/containers/app/pages/page_reducer_stream/index.tsx index 5f29021db09d60..e3dfb402a77857 100644 --- a/examples/response_stream/public/containers/app/pages/page_reducer_stream/index.tsx +++ b/examples/response_stream/public/containers/app/pages/page_reducer_stream/index.tsx @@ -96,13 +96,19 @@ export const PageReducerStream: FC = () => {
- + {buttonLabel} - {progress}% + {progress}% @@ -112,7 +118,9 @@ export const PageReducerStream: FC = () => { -

{getStatusMessage(isRunning, isCancelled, data.progress)}

+

+ {getStatusMessage(isRunning, isCancelled, progress)} +

{
- + {buttonLabel} - {progress}% + {progress}% @@ -118,7 +124,9 @@ export const PageReduxStream: FC = () => { -

{getStatusMessage(isRunning, isCancelled, progress)}

+

+ {getStatusMessage(isRunning, isCancelled, progress)} +

{
- + {buttonLabel} @@ -81,7 +87,7 @@ export const PageSimpleStringStream: FC = () => { /> -

{data}

+

{data}

{errors.length > 0 && ( diff --git a/test/examples/config.js b/test/examples/config.js index 77d73642afd1cb..dd8b49753dba5c 100644 --- a/test/examples/config.js +++ b/test/examples/config.js @@ -31,6 +31,7 @@ export default async function ({ readConfigFile }) { require.resolve('./unified_field_list_examples'), require.resolve('./discover_customization_examples'), require.resolve('./error_boundary'), + require.resolve('./response_stream'), ], services: { ...functionalConfig.get('services'), diff --git a/test/examples/response_stream/index.ts b/test/examples/response_stream/index.ts index b918de669819ba..2f13bf2f9f70cb 100644 --- a/test/examples/response_stream/index.ts +++ b/test/examples/response_stream/index.ts @@ -10,7 +10,17 @@ import { FtrProviderContext } from '../../functional/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function ({ getService, getPageObjects, loadTestFile }: FtrProviderContext) { - describe('response stream', function () { + const browser = getService('browser'); + const PageObjects = getPageObjects(['common', 'header']); + + describe('response-stream', function () { + before(async () => { + await browser.setWindowSize(1300, 900); + await PageObjects.common.navigateToApp('response-stream', { insertTimestamp: false }); + }); + + loadTestFile(require.resolve('./string_stream')); loadTestFile(require.resolve('./reducer_stream')); + loadTestFile(require.resolve('./redux_stream')); }); } diff --git a/test/examples/response_stream/reducer_stream.ts b/test/examples/response_stream/reducer_stream.ts index 001fea1a144c81..4e9c0f9a7af090 100644 --- a/test/examples/response_stream/reducer_stream.ts +++ b/test/examples/response_stream/reducer_stream.ts @@ -6,84 +6,47 @@ * Side Public License, v 1. */ -import fetch from 'node-fetch'; -import { format as formatUrl } from 'url'; - import expect from '@kbn/expect'; - import { FtrProviderContext } from '../../functional/ftr_provider_context'; -import { parseStream } from './parse_stream'; - // eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const config = getService('config'); - const kibanaServerUrl = formatUrl(config.get('servers.kibana')); - - describe('POST /internal/response_stream/reducer_stream', () => { - it('should return full data without streaming', async () => { - const resp = await supertest - .post('/internal/response_stream/reducer_stream') - .set('kbn-xsrf', 'kibana') - .send({ - timeout: 1, - }) - .expect(200); - - expect(Buffer.isBuffer(resp.body)).to.be(true); - - const chunks: string[] = resp.body.toString().split('\n'); - - expect(chunks.length).to.be(201); - - const lastChunk = chunks.pop(); - expect(lastChunk).to.be(''); - - let data: any[] = []; +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + + describe('useReducer stream example', () => { + it('navigates to the example', async () => { + await testSubjects.click('ndjson-usereducer-stream'); + + await retry.try(async () => { + expect(await testSubjects.getVisibleText('responseStreamPageTitle')).to.be( + 'NDJSON useReducer stream' + ); + expect(await testSubjects.getVisibleText('responseStreamProgressBadge')).to.be('0%'); + expect(await testSubjects.getVisibleText('responseStreamStatusMessage')).to.be( + 'Development did not start yet.' + ); + }); + }); - expect(() => { - data = chunks.map((c) => JSON.parse(c)); - }).not.to.throwError(); + it('starts the stream', async () => { + await testSubjects.click('responseStreamStartButton'); - data.forEach((d) => { - expect(typeof d.type).to.be('string'); + await retry.try(async () => { + expect(await testSubjects.getVisibleText('responseStreamProgressBadge')).not.to.be('0%'); + expect(await testSubjects.getVisibleText('responseStreamStatusMessage')).to.be( + 'Development is ongoing, the hype is real!' + ); }); - - const progressData = data.filter((d) => d.type === 'update_progress'); - expect(progressData.length).to.be(100); - expect(progressData[0].payload).to.be(1); - expect(progressData[progressData.length - 1].payload).to.be(100); }); - it('should return data in chunks with streaming', async () => { - const response = await fetch(`${kibanaServerUrl}/internal/response_stream/reducer_stream`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'kbn-xsrf': 'stream', - }, - body: JSON.stringify({ timeout: 1 }), + it('finishes the stream', async () => { + await retry.tryForTime(60000, async () => { + expect(await testSubjects.getVisibleText('responseStreamProgressBadge')).to.be('100%'); + expect(await testSubjects.getVisibleText('responseStreamStatusMessage')).to.be( + 'Development completed, the release got out the door!' + ); }); - - const stream = response.body; - - expect(stream).not.to.be(null); - - if (stream !== null) { - const progressData: any[] = []; - - for await (const action of parseStream(stream)) { - expect(action.type).not.to.be('error'); - if (action.type === 'update_progress') { - progressData.push(action); - } - } - - expect(progressData.length).to.be(100); - expect(progressData[0].payload).to.be(1); - expect(progressData[progressData.length - 1].payload).to.be(100); - } }); }); -}; +} diff --git a/test/examples/response_stream/redux_stream.ts b/test/examples/response_stream/redux_stream.ts new file mode 100644 index 00000000000000..6a9e73d1d35a5d --- /dev/null +++ b/test/examples/response_stream/redux_stream.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../functional/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + + describe('redux stream example', () => { + it('navigates to the example', async () => { + await testSubjects.click('ndjson-redux-toolkit-stream'); + + await retry.try(async () => { + expect(await testSubjects.getVisibleText('responseStreamPageTitle')).to.be( + 'NDJSON Redux Toolkit stream' + ); + expect(await testSubjects.getVisibleText('responseStreamProgressBadge')).to.be('0%'); + expect(await testSubjects.getVisibleText('responseStreamStatusMessage')).to.be( + 'Development did not start yet.' + ); + }); + }); + + it('starts the stream', async () => { + await testSubjects.click('responseStreamStartButton'); + + await retry.try(async () => { + expect(await testSubjects.getVisibleText('responseStreamProgressBadge')).not.to.be('0%'); + expect(await testSubjects.getVisibleText('responseStreamStatusMessage')).to.be( + 'Development is ongoing, the hype is real!' + ); + }); + }); + + it('finishes the stream', async () => { + await retry.tryForTime(60000, async () => { + expect(await testSubjects.getVisibleText('responseStreamProgressBadge')).to.be('100%'); + expect(await testSubjects.getVisibleText('responseStreamStatusMessage')).to.be( + 'Development completed, the release got out the door!' + ); + }); + }); + }); +} diff --git a/test/examples/response_stream/string_stream.ts b/test/examples/response_stream/string_stream.ts new file mode 100644 index 00000000000000..d522b8f5f24848 --- /dev/null +++ b/test/examples/response_stream/string_stream.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../functional/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + + describe('string stream example', () => { + it('navigates to the example', async () => { + await testSubjects.click('simple-string-stream'); + + await retry.try(async () => { + expect(await testSubjects.getVisibleText('responseStreamPageTitle')).to.be( + 'Simple string stream' + ); + expect(await testSubjects.exists('responseStreamStartButton')).to.be(true); + expect(await testSubjects.getVisibleText('responseStreamString')).to.be(''); + }); + }); + + it('starts the stream', async () => { + await testSubjects.click('responseStreamStartButton'); + + await retry.try(async () => { + expect(await testSubjects.getVisibleText('responseStreamString')).not.to.be(''); + }); + }); + + it('finishes the stream', async () => { + await retry.tryForTime(60000, async () => { + expect(await testSubjects.getVisibleText('responseStreamString')).to.be( + 'Elasticsearch is a search engine based on the Lucene library. It provides a distributed, multitenant-capable full-text search engine with an HTTP web interface and schema-free JSON documents. Elasticsearch is developed in Java and is dual-licensed under the source-available Server Side Public License and the Elastic license, while other parts fall under the proprietary (source-available) Elastic License. Official clients are available in Java, .NET (C#), PHP, Python, Apache Groovy, Ruby and many other languages. According to the DB-Engines ranking, Elasticsearch is the most popular enterprise search engine.' + ); + }); + }); + }); +}