From 2ed6ca360fcaf83ab2eb50f85240a19cd0ebc64d Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Mon, 12 Aug 2024 15:43:42 +0200 Subject: [PATCH] Extensions: e2e test usePluginComponent hook (#91750) * add simple test apps that use usePluginComponent hook and exposeComponent api * add e2e test * update readme * Update README.md * fix lint issue * pr feedback --- devenv/plugins.yaml | 8 +++++ .../app-with-exposed-components/README.md | 22 ++++++++++++ .../app-with-exposed-components/img/logo.svg | 1 + .../app-with-exposed-components/module.js | 28 +++++++++++++++ .../app-with-exposed-components/plugin.json | 35 +++++++++++++++++++ .../myorg-componentexposer-app/img/logo.svg | 1 + .../myorg-componentexposer-app/module.js | 14 ++++++++ .../myorg-componentexposer-app/plugin.json | 35 +++++++++++++++++++ .../app-with-extension-point/plugin.json | 4 +-- .../plugins/myorg-b-app/plugin.json | 18 +++++----- .../{ => extensions}/extensionPoints.spec.ts | 0 .../{ => extensions}/extensions.spec.ts | 0 .../extensions/useExposedComponent.spec.ts | 9 +++++ 13 files changed, 162 insertions(+), 13 deletions(-) create mode 100644 e2e/custom-plugins/app-with-exposed-components/README.md create mode 100644 e2e/custom-plugins/app-with-exposed-components/img/logo.svg create mode 100644 e2e/custom-plugins/app-with-exposed-components/module.js create mode 100644 e2e/custom-plugins/app-with-exposed-components/plugin.json create mode 100644 e2e/custom-plugins/app-with-exposed-components/plugins/myorg-componentexposer-app/img/logo.svg create mode 100644 e2e/custom-plugins/app-with-exposed-components/plugins/myorg-componentexposer-app/module.js create mode 100644 e2e/custom-plugins/app-with-exposed-components/plugins/myorg-componentexposer-app/plugin.json rename e2e/plugin-e2e/plugin-e2e-api-tests/as-admin-user/{ => extensions}/extensionPoints.spec.ts (100%) rename e2e/plugin-e2e/plugin-e2e-api-tests/as-admin-user/{ => extensions}/extensions.spec.ts (100%) create mode 100644 e2e/plugin-e2e/plugin-e2e-api-tests/as-admin-user/extensions/useExposedComponent.spec.ts diff --git a/devenv/plugins.yaml b/devenv/plugins.yaml index 9e488cc065f..097428a6ca9 100644 --- a/devenv/plugins.yaml +++ b/devenv/plugins.yaml @@ -17,3 +17,11 @@ apps: org_id: 1 org_name: Main Org. disabled: false + - type: myorg-componentconsumer-app + org_id: 1 + org_name: Main Org. + disabled: false + - type: myorg-componentexposer-app + org_id: 1 + org_name: Main Org. + disabled: false diff --git a/e2e/custom-plugins/app-with-exposed-components/README.md b/e2e/custom-plugins/app-with-exposed-components/README.md new file mode 100644 index 00000000000..03590601496 --- /dev/null +++ b/e2e/custom-plugins/app-with-exposed-components/README.md @@ -0,0 +1,22 @@ +# App with exposed components + +This directory contains two apps - `myorg-componentconsumer-app` and `myorg-componentexposer-app` which is nested inside `myorg-componentconsumer-app`. + +`myorg-componentconsumer-app` exposes a simple React component using the [`exposeComponent`](https://grafana.com/developers/plugin-tools/reference/ui-extensions#exposecomponent) api. `myorg-componentconsumer-app` in turn, consumes this compoment using the [`https://grafana.com/developers/plugin-tools/reference/ui-extensions#useplugincomponent`](https://grafana.com/developers/plugin-tools/reference/ui-extensions#useplugincomponent) hook. + +To test this app: + +```sh +# start e2e test instance (it will install this plugin) +PORT=3000 ./scripts/grafana-server/start-server +# run Playwright tests using Playwright VSCode extension or with the following script +yarn e2e:playwright +``` + +or + +``` +PORT=3000 ./scripts/grafana-server/start-server +yarn start +yarn e2e +``` diff --git a/e2e/custom-plugins/app-with-exposed-components/img/logo.svg b/e2e/custom-plugins/app-with-exposed-components/img/logo.svg new file mode 100644 index 00000000000..3d284dea3af --- /dev/null +++ b/e2e/custom-plugins/app-with-exposed-components/img/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/e2e/custom-plugins/app-with-exposed-components/module.js b/e2e/custom-plugins/app-with-exposed-components/module.js new file mode 100644 index 00000000000..b73fbd617ce --- /dev/null +++ b/e2e/custom-plugins/app-with-exposed-components/module.js @@ -0,0 +1,28 @@ +define(['@grafana/data', '@grafana/runtime', 'react'], function (grafanaData, grafanaRuntime, React) { + var AppPlugin = grafanaData.AppPlugin; + var usePluginComponent = grafanaRuntime.usePluginComponent; + + var MyComponent = function () { + var plugin = usePluginComponent('myorg-componentexposer-app/reusable-component/v1'); + var TestComponent = plugin.component; + var isLoading = plugin.isLoading; + + if (!TestComponent) { + return null; + } + + return React.createElement( + React.Fragment, + null, + React.createElement('div', null, 'Exposed component:'), + isLoading ? 'Loading..' : React.createElement(TestComponent, { name: 'World' }) + ); + }; + + var App = function () { + return React.createElement('div', null, 'Hello Grafana!', React.createElement(MyComponent, null)); + }; + + var plugin = new AppPlugin().setRootPage(App); + return { plugin: plugin }; +}); diff --git a/e2e/custom-plugins/app-with-exposed-components/plugin.json b/e2e/custom-plugins/app-with-exposed-components/plugin.json new file mode 100644 index 00000000000..caf74b2d1a8 --- /dev/null +++ b/e2e/custom-plugins/app-with-exposed-components/plugin.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://raw.githubusercontent.com/grafana/grafana/main/docs/sources/developers/plugins/plugin.schema.json", + "type": "app", + "name": "Extensions exposed component App", + "id": "myorg-componentconsumer-app", + "preload": true, + "info": { + "keywords": ["app"], + "description": "Example on how to extend grafana ui from a plugin", + "author": { + "name": "Myorg" + }, + "logos": { + "small": "img/logo.svg", + "large": "img/logo.svg" + }, + "screenshots": [], + "version": "1.0.0", + "updated": "2024-08-09" + }, + "includes": [ + { + "type": "page", + "name": "Default", + "path": "/a/myorg-componentconsumer-app", + "role": "Admin", + "addToNav": true, + "defaultNav": true + } + ], + "dependencies": { + "grafanaDependency": ">=10.3.3", + "plugins": [] + } +} diff --git a/e2e/custom-plugins/app-with-exposed-components/plugins/myorg-componentexposer-app/img/logo.svg b/e2e/custom-plugins/app-with-exposed-components/plugins/myorg-componentexposer-app/img/logo.svg new file mode 100644 index 00000000000..3d284dea3af --- /dev/null +++ b/e2e/custom-plugins/app-with-exposed-components/plugins/myorg-componentexposer-app/img/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/e2e/custom-plugins/app-with-exposed-components/plugins/myorg-componentexposer-app/module.js b/e2e/custom-plugins/app-with-exposed-components/plugins/myorg-componentexposer-app/module.js new file mode 100644 index 00000000000..4ccaba8ca36 --- /dev/null +++ b/e2e/custom-plugins/app-with-exposed-components/plugins/myorg-componentexposer-app/module.js @@ -0,0 +1,14 @@ +define(['@grafana/data', 'module', 'react'], function (grafanaData, amdModule, React) { + const plugin = new grafanaData.AppPlugin().exposeComponent({ + id: 'myorg-componentexposer-app/reusable-component/v1', + title: 'Reusable component', + description: 'A component that can be reused by other app plugins.', + component: function ({ name }) { + return React.createElement('div', { 'data-testid': 'exposed-component' }, 'Hello ', name, '!'); + }, + }); + + return { + plugin: plugin, + }; +}); diff --git a/e2e/custom-plugins/app-with-exposed-components/plugins/myorg-componentexposer-app/plugin.json b/e2e/custom-plugins/app-with-exposed-components/plugins/myorg-componentexposer-app/plugin.json new file mode 100644 index 00000000000..3487cd45540 --- /dev/null +++ b/e2e/custom-plugins/app-with-exposed-components/plugins/myorg-componentexposer-app/plugin.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://raw.githubusercontent.com/grafana/grafana/main/docs/sources/developers/plugins/plugin.schema.json", + "type": "app", + "name": "A App", + "id": "myorg-componentexposer-app", + "preload": true, + "info": { + "keywords": ["app"], + "description": "Will extend root app with ui extensions", + "author": { + "name": "Myorg" + }, + "logos": { + "small": "img/logo.svg", + "large": "img/logo.svg" + }, + "screenshots": [], + "version": "%VERSION%", + "updated": "%TODAY%" + }, + "includes": [ + { + "type": "page", + "name": "Default", + "path": "/a/myorg-componentexposer-app", + "role": "Admin", + "addToNav": false, + "defaultNav": false + } + ], + "dependencies": { + "grafanaDependency": ">=10.3.3", + "plugins": [] + } +} diff --git a/e2e/custom-plugins/app-with-extension-point/plugin.json b/e2e/custom-plugins/app-with-extension-point/plugin.json index b1d3c396384..3a4ab08faa2 100644 --- a/e2e/custom-plugins/app-with-extension-point/plugin.json +++ b/e2e/custom-plugins/app-with-extension-point/plugin.json @@ -32,7 +32,5 @@ "grafanaDependency": ">=10.3.3", "plugins": [] }, - "generated": { - "extensions": [] - } + "extensions": [] } diff --git a/e2e/custom-plugins/app-with-extension-point/plugins/myorg-b-app/plugin.json b/e2e/custom-plugins/app-with-extension-point/plugins/myorg-b-app/plugin.json index ac501bc7f56..7bd55c0e572 100644 --- a/e2e/custom-plugins/app-with-extension-point/plugins/myorg-b-app/plugin.json +++ b/e2e/custom-plugins/app-with-extension-point/plugins/myorg-b-app/plugin.json @@ -32,14 +32,12 @@ "grafanaDependency": ">=10.3.3", "plugins": [] }, - "generated": { - "extensions": [ - { - "extensionPointId": "plugins/myorg-extensionpoint-app/actions", - "title": "Open from B", - "description": "Open a modal from plugin B", - "type": "link" - } - ] - } + "extensions": [ + { + "extensionPointId": "plugins/myorg-extensionpoint-app/actions", + "title": "Open from B", + "description": "Open a modal from plugin B", + "type": "link" + } + ] } diff --git a/e2e/plugin-e2e/plugin-e2e-api-tests/as-admin-user/extensionPoints.spec.ts b/e2e/plugin-e2e/plugin-e2e-api-tests/as-admin-user/extensions/extensionPoints.spec.ts similarity index 100% rename from e2e/plugin-e2e/plugin-e2e-api-tests/as-admin-user/extensionPoints.spec.ts rename to e2e/plugin-e2e/plugin-e2e-api-tests/as-admin-user/extensions/extensionPoints.spec.ts diff --git a/e2e/plugin-e2e/plugin-e2e-api-tests/as-admin-user/extensions.spec.ts b/e2e/plugin-e2e/plugin-e2e-api-tests/as-admin-user/extensions/extensions.spec.ts similarity index 100% rename from e2e/plugin-e2e/plugin-e2e-api-tests/as-admin-user/extensions.spec.ts rename to e2e/plugin-e2e/plugin-e2e-api-tests/as-admin-user/extensions/extensions.spec.ts diff --git a/e2e/plugin-e2e/plugin-e2e-api-tests/as-admin-user/extensions/useExposedComponent.spec.ts b/e2e/plugin-e2e/plugin-e2e-api-tests/as-admin-user/extensions/useExposedComponent.spec.ts new file mode 100644 index 00000000000..9a01139b445 --- /dev/null +++ b/e2e/plugin-e2e/plugin-e2e-api-tests/as-admin-user/extensions/useExposedComponent.spec.ts @@ -0,0 +1,9 @@ +import { test, expect } from '@grafana/plugin-e2e'; + +const pluginId = 'myorg-componentconsumer-app'; +const exposedComponentTestId = 'exposed-component'; + +test('should display component exposed by another app', async ({ page }) => { + await page.goto(`/a/${pluginId}`); + await expect(await page.getByTestId(exposedComponentTestId)).toHaveText('Hello World!'); +});