ADMIN = List.of(SETUP, RECENT_RUNS);
+
+ /** The business empty state shown on the home while no Google API key is set. */
+ public static final String NOT_CONFIGURED_TITLE = "Page speed testing is not set up";
+ public static final String NOT_CONFIGURED_BODY = "Ask an admin to add a Google PageSpeed API key.";
static final int TREND_WEEKS = 26;
@@ -416,6 +427,29 @@ public final class WebPerfWidgets
+ /*******************************************************************************
+ ** Not Configured: the home's business empty state. Shown only while lab tests
+ ** cannot run because no Google API key is set; says who can fix it and names
+ ** no configuration key. Renders nothing once the provider is configured.
+ *******************************************************************************/
+ public static class NotConfigured extends AbstractWidgetRenderer
+ {
+ /*******************************************************************************
+ ** Render.
+ *******************************************************************************/
+ @Override
+ public RenderWidgetOutput render(RenderWidgetInput input) throws QException
+ {
+ if(runtime(input).labRunner() != null)
+ {
+ return (html(""));
+ }
+ return (html("" + Html.escape(NOT_CONFIGURED_TITLE) + "
" + Html.muted(NOT_CONFIGURED_BODY)));
+ }
+ }
+
+
+
/*******************************************************************************
** Setup: what is configured (pages, lab runner, budgets, field data) and
** the next step for each (WebPerfSetupStatus).
diff --git a/src/main/resources/help/qbit-web-performance.yaml b/src/main/resources/help/qbit-web-performance.yaml
index beead63..d6cf5a0 100644
--- a/src/main/resources/help/qbit-web-performance.yaml
+++ b/src/main/resources/help/qbit-web-performance.yaml
@@ -5,7 +5,7 @@ entries:
- key: app:webPerformance;slot:help
summary: Page speed tests, Google field data, budgets and regressions for your site.
content: |
- Use the Setup card to see what is configured and what to do next. Sync your pages, configure a lab runner and review your budgets. The dashboard shows site scores, trends, slow pages, opportunities, field data and recent runs.
+ Sync your pages and review your budgets, then run tests. The dashboard shows site scores, trends, slow pages, opportunities and field data. If page speed testing is not set up, it says so and tells you to ask an admin.
Run **{{label:webPerformanceTestPageSpeed}}** for selected pages or **{{label:webPerformanceRunSiteAudit}}** for all enabled pages. Mobile and desktop are separate runs by default. Your host controls the enabled features, device strategies, daily run limit and scheduler. Without a configured runner, lab tests wait in the queue.
@@ -623,7 +623,9 @@ entries:
content: |
The scheduled check records observations in **{{label:web_performance_change_event}}**. Repeated observations update the existing event instead of creating duplicates.
- key: widget:webPerformanceSetup;slot:label
- summary: Check your tested pages, lab runner, budgets and field-data setup, with the next step for each.
+ summary: Admin only. Check your tested pages, lab runner, budgets and field-data setup, with the next step for each.
+- key: widget:webPerformanceNotConfigured;slot:label
+ summary: Says when page speed testing is not set up and who can fix it.
- key: possibleValueSource:web_performance_target;slot:help
summary: Choose a tested page.
- key: possibleValueSource:web_performance_lab_run;slot:help
diff --git a/src/test/java/com/kingsrook/qbits/webperf/WebPerfP1Test.java b/src/test/java/com/kingsrook/qbits/webperf/WebPerfP1Test.java
index fd12ab9..66315e2 100644
--- a/src/test/java/com/kingsrook/qbits/webperf/WebPerfP1Test.java
+++ b/src/test/java/com/kingsrook/qbits/webperf/WebPerfP1Test.java
@@ -86,6 +86,71 @@ class WebPerfP1Test
+ /*******************************************************************************
+ ** The business home has no provider setup readout and no run-queue widget;
+ ** those are the admin-placeable list.
+ *******************************************************************************/
+ @Test
+ void testHomeIsBusinessOnly()
+ {
+ List home = qInstance.getApp(config.getAppName()).getWidgets();
+ assertThat(home).doesNotContain(config.qualify(WebPerfWidgets.SETUP), config.qualify(WebPerfWidgets.RECENT_RUNS));
+ assertThat(WebPerfWidgets.HOME).doesNotContain(WebPerfWidgets.SETUP, WebPerfWidgets.RECENT_RUNS);
+ assertThat(WebPerfWidgets.ADMIN).containsExactly(WebPerfWidgets.SETUP, WebPerfWidgets.RECENT_RUNS);
+ assertThat(home).contains(config.qualify(WebPerfWidgets.SITE_SCORES), config.qualify(WebPerfWidgets.TREND), config.qualify(WebPerfWidgets.SLOWEST_PAGES),
+ config.qualify(WebPerfWidgets.OPPORTUNITIES), config.qualify(WebPerfWidgets.FIELD_STATUS));
+ for(String name : WebPerfWidgets.ADMIN)
+ {
+ assertThat(qInstance.getWidget(config.qualify(name))).as(name + " is still defined for a host to place").isNotNull();
+ }
+ }
+
+
+
+ /*******************************************************************************
+ ** Unconfigured: a business empty state naming no config key. Configured:
+ ** nothing at all.
+ *******************************************************************************/
+ @Test
+ void testNotConfiguredEmptyState() throws Exception
+ {
+ assertThat(html(WebPerfWidgets.NOT_CONFIGURED, Map.of())).as("configured shows nothing").isEmpty();
+
+ config.withLabRunner(null).withCruxClient(null);
+ String card = html(WebPerfWidgets.NOT_CONFIGURED, Map.of());
+ assertThat(card).contains("Page speed testing is not set up").contains("Ask an admin to add a Google PageSpeed API key.");
+ assertThat(card).doesNotContain("googleApiKey").doesNotContain("qbit config").doesNotContain("environment variable");
+ }
+
+
+
+ /*******************************************************************************
+ ** The admin widgets render for an admin, and are hidden (permission denied
+ ** under enforcement) for a session without the admin permission.
+ *******************************************************************************/
+ @Test
+ void testAdminWidgetsAdminOnly() throws Exception
+ {
+ for(String name : WebPerfWidgets.ADMIN)
+ {
+ assertThat(html(name, Map.of())).as(name + " for an admin").isNotEmpty();
+ }
+
+ WebPerfTestSupport.login(qInstance, "web_performance.read", "web_performance.write", "web_performance.view.hasAccess");
+ for(String name : WebPerfWidgets.ADMIN)
+ {
+ assertThat(qInstance.getWidget(config.qualify(name)).getPermissionRules().getDenyBehavior()).isEqualTo(com.kingsrook.qqq.backend.core.model.metadata.permissions.DenyBehavior.HIDDEN);
+ RenderWidgetInput input = new RenderWidgetInput().withWidgetMetaData(qInstance.getWidget(config.qualify(name)));
+ input.setPermissionEnforcement(com.kingsrook.qqq.backend.core.actions.permissions.PermissionEnforcement.ENFORCE);
+ org.junit.jupiter.api.Assertions.assertThrows(com.kingsrook.qqq.backend.core.exceptions.QPermissionDeniedException.class,
+ () -> new RenderWidgetAction().execute(input), name + " must not render without admin");
+ assertThat(com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper.hasWidgetPermission(input, config.qualify(name))).isFalse();
+ }
+ assertThat(html(WebPerfWidgets.SITE_SCORES, Map.of())).as("business widgets still render").isNotEmpty();
+ }
+
+
+
/*******************************************************************************
** An instance with a content table "page", the QBit wired to it, and the
** local Google stand-in.