Files
grafana/e2e-playwright/dashboard-cujs/scope-redirect.spec.ts
Tobias Skarhed d1064da4cd Scopes: Add RTK Query API client for caching (#115494)
* Scopes API client

* Initial RTK query commit

* Copy API client from generated enterprise folder

* Mock ScopesApiClient for integration tests

* Update e2e tests

* Handle group expansion for dashboard navigation

* Extract integration test mocks

* Move mock to only be for integration tests

* Update path for enterprise sync script

* Re-export mockData

* Disregard caching for search

* Leave name parameters empty

* Disable subscriptions for client requests

* Add functionality to reset cache between mocked requests

* Use grafana-test-utils for scopes integration tests

* Rollback mock setup

* Remove store form window object

* Remove cache helper

* Restore scopenode search functionality

* Improve request erro handling

* Clean up subscription in case subscription: false lies

* Fix logging security risk

* Rewrite tests to cover RTK query usage and improve error catching

* Update USE_LIVE_DATA to be consistent

* Remove unused timout parameter

* Fix error handling

* Make dashboard-navigation test pass
2026-01-13 13:09:08 +01:00

215 lines
8.2 KiB
TypeScript

import { test, expect } from '@grafana/plugin-e2e';
import { applyScopes, openScopesSelector, selectScope, setupScopeRoutes } from '../utils/scope-helpers';
import { testScopesWithRedirect } from '../utils/scopes';
test.use({
featureToggles: {
scopeFilters: true,
groupByVariable: true,
reloadDashboardsOnParamsChange: true,
useScopesNavigationEndpoint: true,
},
});
test.describe('Scope Redirect Functionality', () => {
test('should redirect to custom URL when scope has redirectUrl', async ({ page, gotoDashboardPage }) => {
const scopes = testScopesWithRedirect();
await test.step('Set up routes and navigate to dashboard', async () => {
// Set up routes BEFORE navigation to ensure all requests are mocked
await setupScopeRoutes(page, scopes);
await gotoDashboardPage({ uid: 'cuj-dashboard-1' });
});
await test.step('Open scopes selector', async () => {
await openScopesSelector(page, scopes);
});
await test.step('Select scope with redirectUrl', async () => {
// Select the scope with redirectUrl directly
await selectScope(page, 'sn-redirect-custom', scopes[0]);
});
await test.step('Apply scopes and verify redirect to custom URL', async () => {
await applyScopes(page, [scopes[0]]);
// Verify we were redirected to the custom URL
await expect(page).toHaveURL(/\/d\/cuj-dashboard-2/);
// Also verify the scope was applied by checking the URL contains the scope
await expect(page).toHaveURL(/scopes=scope-sn-redirect-custom/);
});
});
test('should prioritize redirectUrl over scope navigation fallback', async ({ page, gotoDashboardPage }) => {
const scopes = testScopesWithRedirect();
await test.step('Set up routes and navigate to dashboard', async () => {
await setupScopeRoutes(page, scopes);
await gotoDashboardPage({ uid: 'cuj-dashboard-1' });
});
await test.step('Open scopes selector', async () => {
await openScopesSelector(page, scopes);
});
await test.step('Select scope with redirectUrl', async () => {
// Select the scope with redirectUrl directly
await selectScope(page, 'sn-redirect-custom', scopes[0]);
});
await test.step('Apply scopes and verify redirectUrl takes priority', async () => {
await applyScopes(page, [scopes[0]]);
// Should redirect to custom URL, not stay on current dashboard
await expect(page).toHaveURL(/\/d\/cuj-dashboard-2/);
await expect(page).not.toHaveURL(/\/d\/cuj-dashboard-1/);
// Verify the scope was applied
await expect(page).toHaveURL(/scopes=scope-sn-redirect-custom/);
});
});
test('should not redirect when reloading page on dashboard not in dashboard list', async ({
page,
gotoDashboardPage,
}) => {
const scopes = testScopesWithRedirect();
await test.step('Set up routes and navigate to dashboard', async () => {
await setupScopeRoutes(page, scopes);
await gotoDashboardPage({ uid: 'cuj-dashboard-1' });
});
await test.step('Select and apply scope', async () => {
await openScopesSelector(page, scopes);
await selectScope(page, 'sn-redirect-fallback', scopes[1]);
await applyScopes(page, [scopes[1]]);
// Verify the scope was applied
await expect(page).toHaveURL(/scopes=scope-sn-redirect-fallback/);
});
await test.step('Navigate to dashboard not in scope dashboard list', async () => {
// Navigate to a dashboard that is not in the scope dashboard bindings
// Preserve the scope parameter using queryParams
await gotoDashboardPage({
uid: 'cuj-dashboard-3',
queryParams: new URLSearchParams({ scopes: 'scope-sn-redirect-fallback' }),
});
// Verify we're on cuj-dashboard-3 with the scope still applied
await expect(page).toHaveURL(/\/d\/cuj-dashboard-3/);
await expect(page).toHaveURL(/scopes=scope-sn-redirect-fallback/);
});
await test.step('Reload page and verify no redirect', async () => {
// Reload the page with the scope still selected
await page.reload();
// Wait for the page to load
await page.waitForLoadState('networkidle');
// Should stay on the same dashboard (cuj-dashboard-3), not redirect
await expect(page).toHaveURL(/\/d\/cuj-dashboard-3/);
// Verify the scope is still applied
await expect(page).toHaveURL(/scopes=scope-sn-redirect-fallback/);
});
});
test('should not redirect when deselecting scopes on dashboard not in dashboard list', async ({
page,
gotoDashboardPage,
}) => {
const scopes = testScopesWithRedirect();
await test.step('Set up routes and navigate to dashboard', async () => {
await setupScopeRoutes(page, scopes);
await gotoDashboardPage({ uid: 'cuj-dashboard-1' });
});
await test.step('Select and apply scope', async () => {
await openScopesSelector(page, scopes);
await selectScope(page, 'sn-redirect-fallback', scopes[1]);
await applyScopes(page, [scopes[1]]);
// Verify the scope was applied
await expect(page).toHaveURL(/scopes=scope-sn-redirect-fallback/);
});
await test.step('Navigate to dashboard not in scope dashboard list', async () => {
// Navigate to a dashboard that is not in the scope dashboard bindings
// Preserve the scope parameter using queryParams
await gotoDashboardPage({
uid: 'cuj-dashboard-3',
queryParams: new URLSearchParams({ scopes: 'scope-sn-redirect-fallback' }),
});
// Verify we're on cuj-dashboard-3 with the scope still applied
await expect(page).toHaveURL(/\/d\/cuj-dashboard-3/);
await expect(page).toHaveURL(/scopes=scope-sn-redirect-fallback/);
});
await test.step('Deselect scopes and verify no redirect', async () => {
// Click the clear button to remove all scopes
await page.getByTestId('scopes-selector-input').hover();
await page.getByTestId('scopes-selector-input-clear').click();
// Should stay on the same dashboard (cuj-dashboard-3), not redirect
await expect(page).toHaveURL(/\/d\/cuj-dashboard-3/);
// Verify the scope is no longer in the URL
await expect(page).not.toHaveURL(/scopes=/);
});
});
test('should not redirect to redirectPath when on active scope navigation', async ({ page, gotoDashboardPage }) => {
const scopes = testScopesWithRedirect();
await test.step('Set up routes and navigate to dashboard', async () => {
await setupScopeRoutes(page, scopes);
await gotoDashboardPage({ uid: 'cuj-dashboard-1' });
});
await test.step('Set up scope navigation to dashboard-1', async () => {
// First, apply a scope that creates scope navigation to dashboard-1 (without redirectPath)
await openScopesSelector(page, scopes);
await selectScope(page, 'sn-redirect-setup', scopes[2]);
await applyScopes(page, [scopes[2]]);
// Verify we're on dashboard-1 with the scope applied
await expect(page).toHaveURL(/\/d\/cuj-dashboard-1/);
await expect(page).toHaveURL(/scopes=scope-sn-redirect-setup/);
});
await test.step('Navigate to dashboard-1 to be on active scope navigation', async () => {
// Navigate to dashboard-1 which is now a scope navigation target
await gotoDashboardPage({
uid: 'cuj-dashboard-1',
queryParams: new URLSearchParams({ scopes: 'scope-sn-redirect-setup' }),
});
// Verify we're on dashboard-1
await expect(page).toHaveURL(/\/d\/cuj-dashboard-1/);
});
await test.step('Apply scope with redirectPath and verify no redirect', async () => {
// Now apply a different scope that has redirectPath
// Since we're on an active scope navigation, it should NOT redirect
await openScopesSelector(page, scopes);
await selectScope(page, 'sn-redirect-with-navigation', scopes[3]);
await applyScopes(page, [scopes[3]]);
// Verify the new scope was applied
await expect(page).toHaveURL(/scopes=scope-sn-redirect-with-navigation/);
// Since we're already on the active scope navigation (dashboard-1),
// we should NOT redirect to redirectPath (dashboard-3)
await expect(page).toHaveURL(/\/d\/cuj-dashboard-1/);
await expect(page).not.toHaveURL(/\/d\/cuj-dashboard-3/);
});
});
});