Skip to content

Commit

Permalink
temp changes
Browse files Browse the repository at this point in the history
  • Loading branch information
brojd committed Jun 4, 2024
1 parent 3d15bdc commit b00f1c4
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,41 +36,78 @@ Then OnCall loads as usual
import { test, expect } from '../fixtures';
import { clickButton } from '../utils/forms';
import { goToGrafanaPage, goToOnCallPage } from '../utils/navigation';
import { createGrafanaUser } from '../utils/users';

test.describe('Plugin initialization', () => {
test('Plugin works for new viewer user right away', async ({ adminRolePage: { page } }) => {
test('Plugin OnCall pages work for new viewer user right away', async ({ adminRolePage: { page } }) => {
// Create new viewer user
const USER_NAME = `viewer-${new Date().getTime()}`;
await goToGrafanaPage(page, '/admin/users');
await page.getByRole('link', { name: 'New user' }).click();
await page.getByLabel('Name *').fill(USER_NAME);
await page.getByLabel('Username').fill(USER_NAME);
await page.getByLabel('Password *').fill(USER_NAME);
await clickButton({ page, buttonText: 'Create user' });
await page.waitForTimeout(2000);
await createGrafanaUser(page, USER_NAME);

// Login as new user
await goToGrafanaPage(page, '/logout');
await page.getByLabel('Email or username').fill(USER_NAME);
await page.getByLabel(/Password/).fill(USER_NAME);
await clickButton({ page, buttonText: 'Log in' });
await page.getByText('Welcome to Grafana').waitFor();

// Start tracking HTTP response codes
// Wait till Grafana home page is loaded and start tracking HTTP response codes
await page.getByText('Welcome to Grafana').waitFor();
await page.waitForLoadState('networkidle');
const networkResponseStatuses: number[] = [];
page.on('requestfinished', async (request) => networkResponseStatuses.push((await request.response()).status()));

// Go to OnCall
// Go to OnCall and assert that none of the requests failed
await goToOnCallPage(page, 'alert-groups');
const allRequestsPassed = networkResponseStatuses.every(
(status) => `${status}`.startsWith('2') || `${status}`.startsWith('3')
);
expect(allRequestsPassed).toBeTruthy();

// ...and user sees content of alert groups page
await expect(page.getByText('No alert groups found')).toBeVisible();
});

test('Extension registered by OnCall plugin works for new editor user right away', async ({
adminRolePage: { page },
}) => {
// Create new editor user
const USER_NAME = `editor-${new Date().getTime()}`;
await createGrafanaUser(page, USER_NAME);
await clickButton({ page, buttonText: 'Create user' });
await clickButton({ page, buttonText: 'Change role' });
await page
.locator('div')
.filter({ hasText: /^Viewer$/ })
.nth(1)
.click();
await page.getByText(/Editor/).click();
await clickButton({ page, buttonText: 'Save' });

// Assert that none of the requests failed
// Login as new user
await goToGrafanaPage(page, '/logout');
await page.getByLabel('Email or username').fill(USER_NAME);
await page.getByLabel(/Password/).fill(USER_NAME);
await clickButton({ page, buttonText: 'Log in' });

// Wait till Grafana home page is loaded and start tracking HTTP response codes
await page.getByText('Welcome to Grafana').waitFor();
await page.waitForLoadState('networkidle');
const networkResponseStatuses: number[] = [];
page.on('requestfinished', async (request) => networkResponseStatuses.push((await request.response()).status()));

// Go to profile -> IRM tab where OnCall plugin extension is registered
await goToGrafanaPage(page, '/profile?tab=irm');
const allRequestsPassed = networkResponseStatuses.every(
(status) => `${status}`.startsWith('2') || `${status}`.startsWith('3')
);
expect(allRequestsPassed).toBeTruthy();

// // ...and user sees conent of alert groups page
// await expect(page.getByText('No alert groups found')).toBeVisible();
console.log(networkResponseStatuses);

// ...and user sees content of alert groups page
const extensionContentText = page.getByText('Please connect Grafana Cloud OnCall to use the mobile app');
await extensionContentText.waitFor();
await expect(extensionContentText).toBeVisible();
});
});

Expand Down
12 changes: 11 additions & 1 deletion grafana-plugin/e2e-tests/utils/users.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Page, expect } from '@playwright/test';

Check failure on line 1 in grafana-plugin/e2e-tests/utils/users.ts

View workflow job for this annotation

GitHub Actions / Lint, test, and build frontend

There should be at least one empty line between import groups
import { clickButton } from './forms';

Check failure on line 2 in grafana-plugin/e2e-tests/utils/users.ts

View workflow job for this annotation

GitHub Actions / Lint, test, and build frontend

There should be no empty line within import group

import { goToOnCallPage } from './navigation';
import { goToGrafanaPage, goToOnCallPage } from './navigation';

export async function accessProfileTabs(page: Page, tabs: string[], hasAccess: boolean) {
await goToOnCallPage(page, 'users');
Expand Down Expand Up @@ -43,3 +44,12 @@ export async function viewUsers(page: Page, isAllowedToView = true): Promise<voi
);
}
}

export const createGrafanaUser = async (page: Page, username: string): Promise<void> => {
await goToGrafanaPage(page, '/admin/users');
await page.getByRole('link', { name: 'New user' }).click();
await page.getByLabel('Name *').fill(username);
await page.getByLabel('Username').fill(username);
await page.getByLabel('Password *').fill(username);
await clickButton({ page, buttonText: 'Create user' });
};
2 changes: 1 addition & 1 deletion grafana-plugin/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default defineConfig({
reporter: [['html', { open: IS_CI ? 'never' : 'always' }]],

/* Maximum time one test can run for. */
timeout: 60_000,
timeout: 20_000,
expect: {
/**
* Maximum time expect() should wait for the condition to be met.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { DisconnectButton } from './parts/DisconnectButton/DisconnectButton';
import { DownloadIcons } from './parts/DownloadIcons/DownloadIcons';
import { LinkLoginButton } from './parts/LinkLoginButton/LinkLoginButton';
import { QRCode } from './parts/QRCode/QRCode';

Check failure on line 23 in grafana-plugin/src/containers/MobileAppConnection/MobileAppConnection.tsx

View workflow job for this annotation

GitHub Actions / Lint, test, and build frontend

There should be at least one empty line between import groups
import { useInitializePlugin } from 'utils/hooks';

Check failure on line 24 in grafana-plugin/src/containers/MobileAppConnection/MobileAppConnection.tsx

View workflow job for this annotation

GitHub Actions / Lint, test, and build frontend

`utils/hooks` import should occur before import of `utils/utils`

const cx = cn.bind(styles);

Expand Down Expand Up @@ -364,6 +365,7 @@ function QRLoading() {

export const MobileAppConnectionWrapper: React.FC<{}> = observer(() => {
const { userStore } = store;
const {} = useInitializePlugin({ forceReinstall: true });

useEffect(() => {
loadData();
Expand Down
2 changes: 1 addition & 1 deletion grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import { getQueryParams, isTopNavbar } from './GrafanaPluginRootPage.helpers';
import grafanaGlobalStyle from '!raw-loader!assets/style/grafanaGlobalStyles.css';

export const GrafanaPluginRootPage = (props: AppRootProps) => {
const { isInitialized } = useInitializePlugin(props);
const { isInitialized } = useInitializePlugin({ appRootProps: props });

useOnMount(() => {
FaroHelper.initializeFaro(getOnCallApiUrl(props.meta));
Expand Down
2 changes: 1 addition & 1 deletion grafana-plugin/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export type OnCallPluginMetaSecureJSONData = {
onCallApiToken: string;
};

export type AppRootProps = BaseAppRootProps<OnCallPluginMetaJSONData>;
export type AppRootProps = BaseAppRootProps<OnCallPluginMetaJSONData> & { forceReinstall?: boolean };

// NOTE: it is possible that plugin.meta.jsonData is null (ex. on first-ever setup)
// the typing on AppPluginMeta does not seem correct atm..
Expand Down
24 changes: 19 additions & 5 deletions grafana-plugin/src/utils/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import { LoaderHelper } from 'models/loader/loader.helpers';
import { makeRequest } from 'network/network';
import { useStore } from 'state/useStore';

import { config } from '@grafana/runtime';

Check failure on line 12 in grafana-plugin/src/utils/hooks.tsx

View workflow job for this annotation

GitHub Actions / Lint, test, and build frontend

There should be at least one empty line between import groups

Check failure on line 12 in grafana-plugin/src/utils/hooks.tsx

View workflow job for this annotation

GitHub Actions / Lint, test, and build frontend

`@grafana/runtime` import should occur before import of `@grafana/ui`

Check warning on line 12 in grafana-plugin/src/utils/hooks.tsx

View workflow job for this annotation

GitHub Actions / Lint, test, and build frontend

'config' is defined but never used
import { LocationHelper } from './LocationHelper';
import { GRAFANA_LICENSE_OSS } from './consts';

Check warning on line 14 in grafana-plugin/src/utils/hooks.tsx

View workflow job for this annotation

GitHub Actions / Lint, test, and build frontend

'GRAFANA_LICENSE_OSS' is defined but never used
import { getCommonStyles } from './styles';
import { getIsRunningOpenSourceVersion } from './utils';

export function useForceUpdate() {
const [, setValue] = useState(0);
Expand Down Expand Up @@ -142,8 +144,14 @@ export const useOnMount = (callback: () => void) => {
}, []);
};

export const useInitializePlugin = ({ meta }: AppRootProps) => {
const IS_OPEN_SOURCE = meta?.jsonData?.license === GRAFANA_LICENSE_OSS;
export const useInitializePlugin = ({
appRootProps,
forceReinstall,
}: {
appRootProps?: AppRootProps;
forceReinstall?: boolean;
}) => {
const IS_OPEN_SOURCE = getIsRunningOpenSourceVersion();
const [isInitialized, setIsInitialized] = useState(false);

// create oncall api token and save in plugin settings
Expand All @@ -154,17 +162,23 @@ export const useInitializePlugin = ({ meta }: AppRootProps) => {
};

const initializePlugin = async () => {
if (!meta?.secureJsonFields?.onCallApiToken) {
if (forceReinstall || !appRootProps?.meta?.secureJsonFields?.onCallApiToken) {
await install();
}

// trigger users sync
let shouldReinstall = false;
try {
await makeRequest(`/plugin/status`, {
const { token_ok } = await makeRequest(`/plugin/status`, {
method: 'POST',
});
shouldReinstall = !token_ok;
} catch (_err) {
await install();
shouldReinstall = true;
} finally {
if (shouldReinstall) {
await install();
}
}

setIsInitialized(true);
Expand Down
3 changes: 3 additions & 0 deletions grafana-plugin/src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AppEvents } from '@grafana/data';
import { config } from '@grafana/runtime';
import { AxiosError } from 'axios';
import { sentenceCase } from 'change-case';
// @ts-ignore
Expand Down Expand Up @@ -118,3 +119,5 @@ function isFieldEmpty(value: any): boolean {
export const allFieldsEmpty = (obj: any) => every(obj, isFieldEmpty);

export const isMobile = window.matchMedia('(max-width: 768px)').matches;

export const getIsRunningOpenSourceVersion = () => config.apps['grafana-oncall-app'].version.startsWith('r');

0 comments on commit b00f1c4

Please sign in to comment.