chore(integration-test): remove the outdated-setup (#7887)

* chore(integration-test): remove the outdated-setup

* chore(integration-test): remove the outdated-setup
This commit is contained in:
Vikrant Gupta 2025-05-11 17:10:55 +05:30 committed by GitHub
parent 815a6d13c5
commit 1d379931b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
68 changed files with 2 additions and 2158 deletions

2
.gitignore vendored
View File

@ -60,9 +60,7 @@ ee/query-service/db
e2e/node_modules/
e2e/test-results/
e2e/playwright-report/
e2e/blob-report/
e2e/playwright/.cache/
e2e/.auth
# go

View File

@ -3,5 +3,4 @@ BUNDLE_ANALYSER="true"
FRONTEND_API_ENDPOINT="http://localhost:8080/"
INTERCOM_APP_ID="intercom-app-id"
PLAYWRIGHT_TEST_BASE_URL="http://localhost:8080"
CI="1"

View File

@ -30,11 +30,6 @@ const config: Config.InitialOptions = {
testPathIgnorePatterns: ['/node_modules/', '/public/'],
moduleDirectories: ['node_modules', 'src'],
testEnvironment: 'jest-environment-jsdom',
testEnvironmentOptions: {
'jest-playwright': {
browsers: ['chromium', 'firefox', 'webkit'],
},
},
coverageThreshold: {
global: {
statements: 80,

View File

@ -15,10 +15,6 @@
"jest:coverage": "jest --coverage",
"jest:watch": "jest --watch",
"postinstall": "yarn i18n:generate-hash && (is-ci || yarn husky:configure)",
"playwright": "NODE_ENV=testing playwright test --config=./playwright.config.ts",
"playwright:local:debug": "PWDEBUG=console yarn playwright --headed --browser=chromium",
"playwright:codegen:local": "playwright codegen http://localhost:3301",
"playwright:codegen:local:auth": "yarn playwright:codegen:local --load-storage=tests/auth.json",
"husky:configure": "cd .. && husky install frontend/.husky && cd frontend && chmod ug+x .husky/*",
"commitlint": "commitlint --edit $1",
"test": "jest",
@ -164,7 +160,6 @@
"@commitlint/config-conventional": "^16.2.4",
"@faker-js/faker": "9.3.0",
"@jest/globals": "^27.5.1",
"@playwright/test": "^1.22.0",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "13.4.0",
"@testing-library/user-event": "14.4.3",

View File

@ -1,23 +0,0 @@
import { PlaywrightTestConfig } from '@playwright/test';
import dotenv from 'dotenv';
dotenv.config();
const config: PlaywrightTestConfig = {
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
preserveOutput: 'always',
name: 'Signoz',
testDir: './tests',
use: {
trace: 'retain-on-failure',
baseURL: process.env.PLAYWRIGHT_TEST_BASE_URL || 'http://localhost:3301',
},
updateSnapshots: 'all',
fullyParallel: !!process.env.CI,
quiet: false,
testMatch: ['**/*.spec.ts'],
reporter: process.env.CI ? 'github' : 'list',
};
export default config;

View File

@ -9,7 +9,7 @@ done
# create temporary tsconfig which includes only passed files
str="{
\"extends\": \"./tsconfig.json\",
\"include\": [ \"src/typings/**/*.ts\",\"src/**/*.d.ts\", \"./babel.config.js\", \"./jest.config.ts\", \"./.eslintrc.js\",\"./__mocks__\",\"./conf/default.conf\",\"./public\",\"./tests\",\"./playwright.config.ts\",\"./commitlint.config.ts\",\"./webpack.config.js\",\"./webpack.config.prod.js\",\"./jest.setup.ts\",\"./**/*.d.ts\",$files]
\"include\": [ \"src/typings/**/*.ts\",\"src/**/*.d.ts\", \"./babel.config.js\", \"./jest.config.ts\", \"./.eslintrc.js\",\"./__mocks__\",\"./public\",\"./tests\",\"./commitlint.config.ts\",\"./webpack.config.js\",\"./webpack.config.prod.js\",\"./jest.setup.ts\",\"./**/*.d.ts\",$files]
}"
echo $str > tsconfig.tmp

View File

@ -1,34 +0,0 @@
{
"cookies": [],
"origins": [
{
"origin": "http://localhost:3301",
"localStorage": [
{
"name": "metricsTimeDurations",
"value": "{}"
},
{
"name": "i18nextLng",
"value": "en-US"
},
{
"name": "reactQueryDevtoolsSortFn",
"value": "\"Status > Last Updated\""
},
{
"name": "AUTH_TOKEN",
"value": "authtoken"
},
{
"name": "IS_LOGGED_IN",
"value": "true"
},
{
"name": "REFRESH_AUTH_TOKEN",
"value": "refreshJwt"
}
]
}
]
}

View File

@ -1,143 +0,0 @@
import { Page, test, expect } from '@playwright/test';
import { loginApi } from '../fixtures/common';
import ROUTES from 'constants/routes';
import dashboardsListEmptyResponse from '../fixtures/api/dashboard/getDashboardListEmpty200.json';
import createNewDashboardPostResponse from '../fixtures/api/dashboard/createNewDashboardPost200.json';
import queryRangeSuccessResponse from '../fixtures/api/traces/queryRange200.json';
import getIndividualDashboardResponse from '../fixtures/api/dashboard/getIndividualDashboard200.json';
import putNewDashboardResponse from '../fixtures/api/dashboard/putNewDashboardUpdate200.json';
import putDashboardTimeSeriesResponse from '../fixtures/api/dashboard/putDashboardWithTimeSeries200.json';
import dashboardGetCallWithTimeSeriesWidgetResponse from '../fixtures/api/dashboard/dashboardGetCallWithTimeSeriesWidget200.json';
import {
addPanelID,
configureDashboardDescriptonID,
configureDashboardNameID,
configureDashboardSettings,
dashboardDescription,
dashboardHomePageDesc,
dashboardHomePageTitle,
dashboardName,
dashboardsListAndCreate,
getDashboardsListEndpoint,
getIndividualDashboard,
getIndividualDashboardsEndpoint,
getTimeSeriesQueryData,
newDashboardBtnID,
saveConfigureDashboardID,
timeSeriesGraphName,
timeSeriesPanelID,
} from './utils';
let page: Page;
test.describe('Dashboards Landing Page', () => {
test.beforeEach(async ({ baseURL, browser }) => {
const context = await browser.newContext({
storageState: 'tests/auth.json',
});
const newPage = await context.newPage();
await loginApi(newPage);
await newPage.goto(`${baseURL}${ROUTES.APPLICATION}`);
page = newPage;
});
test('Create a new dashboard and configure the name and description', async ({}) => {
// render the dashboards list page with empty response
await dashboardsListAndCreate(page, dashboardsListEmptyResponse);
// navigate to the dashboards landing page
await page.locator(`li[data-menu-id*="/dashboard"]`).click();
await page.waitForRequest(`**/${getDashboardsListEndpoint}`);
// without data we should have no data rendering
const noDataText = await page.getByText('No data');
await expect(noDataText).toBeVisible();
// create a new dashboard
await page.locator(`data-testid=${newDashboardBtnID}`).click();
await dashboardsListAndCreate(page, createNewDashboardPostResponse);
await getIndividualDashboard(page, getIndividualDashboardResponse);
await page.locator(`li[data-menu-id*="Create"]`).click();
await page.waitForRequest(`**/${getIndividualDashboardsEndpoint}`);
await page.locator(`data-testid=${configureDashboardSettings}`).click();
const dashboardNameInput = await page.locator(
`data-testid=${configureDashboardNameID}`,
);
// edit the name of the dashboard
await dashboardNameInput.fill('');
await dashboardNameInput.fill(`${dashboardName}`);
// edit the description of the dashboard
const dashboardDescInput = await page.locator(
`data-testid=${configureDashboardDescriptonID}`,
);
await dashboardDescInput.fill('');
await dashboardDescInput.fill(`${dashboardDescription}`);
await getIndividualDashboard(page, putNewDashboardResponse);
await page.locator(`data-testid=${saveConfigureDashboardID}`).click();
await page.locator(`svg[data-icon="close"]`).click();
// save the configs and check for updated values
const dashboardTitle = await page
.locator(`data-testid=${dashboardHomePageTitle}`)
.textContent();
expect(dashboardTitle).toBe(`${dashboardName}`);
const dashboardDesc = await page
.locator(`data-testid=${dashboardHomePageDesc}`)
.textContent();
expect(dashboardDesc).toBe(`${dashboardDescription}`);
await page.locator(`data-testid=${addPanelID}`).click();
await getIndividualDashboard(page, putDashboardTimeSeriesResponse, true);
await getTimeSeriesQueryData(page, queryRangeSuccessResponse);
await page.locator(`id=${timeSeriesPanelID}`).click();
await page.waitForRequest(`**/${getIndividualDashboardsEndpoint}`);
const panelTitle = await page.getByText('Panel Title').isVisible();
await expect(panelTitle).toBeTruthy();
await page.getByPlaceholder('Title').type(`${timeSeriesGraphName}`);
await page.locator('data-testid=new-widget-save').click();
await getIndividualDashboard(
page,
dashboardGetCallWithTimeSeriesWidgetResponse,
);
await page.locator('span:has-text("OK")').click();
await page.waitForLoadState('networkidle');
const timeSeriesWidget = await await page.locator(
`data-testid=${timeSeriesGraphName}`,
);
await expect(timeSeriesWidget).toBeTruthy();
});
});

View File

@ -1,181 +0,0 @@
import { Page } from '@playwright/test';
import { JsonApplicationType } from '../fixtures/constant';
// API endpoints
export const getDashboardsListEndpoint = 'v1/dashboards';
export const getIndividualDashboardsEndpoint = 'v1/dashboards/**';
export const queryRangeApiEndpoint = 'query_range';
// element's data-testid's
export const newDashboardBtnID = 'create-new-dashboard';
export const configureDashboardSettings = 'show-drawer';
export const configureDashboardNameID = 'dashboard-name';
export const configureDashboardDescriptonID = 'dashboard-desc';
export const dashboardHomePageTitle = 'dashboard-landing-name';
export const dashboardHomePageDesc = 'dashboard-landing-desc';
export const saveConfigureDashboardID = 'save-dashboard-config';
export const addNewVariableID = 'add-new-variable';
export const dashboardName = 'Playwright Dashboard';
export const dashboardDescription = 'Playwright Dashboard Description';
export const addPanelID = 'add-panel';
export const timeSeriesPanelID = 'graph';
export const valuePanelID = 'value';
export const tablePanelID = 'table';
export const timeSeriesGraphName = 'Time1';
let widgetsId: string;
export const insertWidgetIdInResponse = (widgetID: string): any => ({
status: 'success',
data: {
id: 219,
uuid: 'd697fddb-a771-4bb4-aa38-810f000ed96a',
created_at: '2023-11-17T20:44:03.167646604Z',
created_by: 'vikrant@signoz.io',
updated_at: '2023-11-17T20:51:23.058536475Z',
updated_by: 'vikrant@signoz.io',
data: {
description: 'Playwright Dashboard T',
layout: [
{
h: 3,
i: '9fbcf0db-1572-4572-bf6b-0a84dd10ed85',
w: 6,
x: 0,
y: 0,
},
],
version: 'v3',
name: '',
tags: [],
title: 'Playwright Dashboard',
variables: {},
widgets: [
{
description: '',
id: widgetID,
isStacked: false,
nullZeroValues: '',
opacity: '',
panelTypes: 'graph',
query: {
builder: {
queryData: [
{
aggregateAttribute: {
dataType: '',
id: '------',
isColumn: false,
isJSON: false,
key: '',
type: '',
},
aggregateOperator: 'count',
dataSource: 'metrics',
disabled: false,
expression: 'A',
filters: {
items: [],
op: 'AND',
},
groupBy: [],
having: [],
legend: '',
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
stepInterval: 60,
},
],
queryFormulas: [],
},
clickhouse_sql: [
{
disabled: false,
legend: '',
name: 'A',
query: '',
},
],
id: '6b4011e4-bcea-497d-81a9-0ee7816b679d',
promql: [
{
disabled: false,
legend: '',
name: 'A',
query: '',
},
],
queryType: 'builder',
},
timePreferance: 'GLOBAL_TIME',
title: '',
},
],
},
isLocked: 0,
},
});
// mock API calls
export const dashboardsListAndCreate = async (
page: Page,
response: any,
): Promise<void> => {
await page.route(`**/${getDashboardsListEndpoint}`, (route) =>
route.fulfill({
status: 200,
contentType: JsonApplicationType,
json: response,
}),
);
};
export const getIndividualDashboard = async (
page: Page,
response?: any,
useRequestObject?: boolean,
): Promise<void> => {
await page.route(`**/${getIndividualDashboardsEndpoint}`, (route, request) => {
if (useRequestObject && request.method() === 'PUT') {
widgetsId = request.postDataJSON()?.widgets[0].id;
}
route.fulfill({
status: 200,
contentType: JsonApplicationType,
json: useRequestObject ? insertWidgetIdInResponse(widgetsId) : response,
});
});
};
export const getTimeSeriesQueryData = async (
page: Page,
response: any,
): Promise<void> => {
// eslint-disable-next-line sonarjs/no-identical-functions
await page.route(`**/${queryRangeApiEndpoint}`, (route): any =>
route.fulfill({
status: 200,
contentType: JsonApplicationType,
json: response,
}),
);
};

View File

@ -1,101 +0,0 @@
import { expect, Page, test } from '@playwright/test';
import ROUTES from 'constants/routes';
import allErrorList from '../fixtures/api/allErrors/200.json';
import errorDetailSuccess from '../fixtures/api/errorDetails/200.json';
import errorDetailNotFound from '../fixtures/api/errorDetails/404.json';
import nextPreviousSuccess from '../fixtures/api/getNextPrev/200.json';
import { loginApi } from '../fixtures/common';
import { JsonApplicationType } from '../fixtures/constant';
let page: Page;
const timestamp = '1657794588955274000';
test.describe('Expections Details', async () => {
test.beforeEach(async ({ baseURL, browser }) => {
const context = await browser.newContext({ storageState: 'tests/auth.json' });
const newPage = await context.newPage();
await loginApi(newPage);
await newPage.goto(`${baseURL}${ROUTES.APPLICATION}`);
page = newPage;
});
test('Should have not found when api return 404', async () => {
await Promise.all([
page.route('**/errorFromGroupID**', (route) =>
route.fulfill({
status: 404,
contentType: JsonApplicationType,
body: JSON.stringify(errorDetailNotFound),
}),
),
page.route('**/nextPrevErrorIDs**', (route) =>
route.fulfill({
status: 404,
contentType: JsonApplicationType,
body: JSON.stringify([]),
}),
),
]);
await page.goto(
`${ROUTES.ERROR_DETAIL}?groupId=${allErrorList[0].groupID}&timestamp=${timestamp}`,
{
waitUntil: 'networkidle',
},
);
const NoDataLocator = page.locator('text=Not Found');
const isVisible = await NoDataLocator.isVisible();
const text = await NoDataLocator.textContent();
expect(isVisible).toBe(true);
expect(text).toBe('Not Found');
expect(await page.screenshot()).toMatchSnapshot();
});
test('Render Success Data when 200 from details page', async () => {
await Promise.all([
page.route('**/errorFromGroupID**', (route) =>
route.fulfill({
status: 200,
contentType: JsonApplicationType,
body: JSON.stringify(errorDetailSuccess),
}),
),
page.route('**/nextPrevErrorIDs**', (route) =>
route.fulfill({
status: 200,
contentType: JsonApplicationType,
body: JSON.stringify(nextPreviousSuccess),
}),
),
]);
await page.goto(
`${ROUTES.ERROR_DETAIL}?groupId=${allErrorList[0].groupID}&timestamp=${timestamp}`,
{
waitUntil: 'networkidle',
},
);
const traceDetailButton = page.locator('text=See the error in trace graph');
const olderButton = page.locator('text=Older');
const newerButton = page.locator(`text=Newer`);
expect(await traceDetailButton.isVisible()).toBe(true);
expect(await olderButton.isVisible()).toBe(true);
expect(await newerButton.isVisible()).toBe(true);
expect(await traceDetailButton.textContent()).toBe(
'See the error in trace graph',
);
expect(await olderButton.textContent()).toBe('Older');
expect(await newerButton.textContent()).toBe('Newer');
expect(await page.screenshot()).toMatchSnapshot();
});
});

View File

@ -1,148 +0,0 @@
import { expect, Page, test } from '@playwright/test';
import ROUTES from 'constants/routes';
import successAllErrors from '../fixtures/api/allErrors/200.json';
import { loginApi } from '../fixtures/common';
import { JsonApplicationType } from '../fixtures/constant';
const noDataTableData = async (page: Page): Promise<void> => {
const text = page.locator('text=No Data');
expect(text).toBeVisible();
expect(text).toHaveText('No Data');
const textType = [
'Exception Type',
'Error Message',
'Last Seen',
'First Seen',
'Application',
];
textType.forEach(async (text) => {
const textLocator = page.locator(`text=${text}`);
const textContent = await textLocator.textContent();
expect(textContent).toBe(text);
expect(textLocator).not.toBeNull();
expect(textLocator).toBeVisible();
await expect(textLocator).toHaveText(`${text}`);
});
};
let page: Page;
test.describe('Expections page', async () => {
test.beforeEach(async ({ baseURL, browser }) => {
const context = await browser.newContext({ storageState: 'tests/auth.json' });
const newPage = await context.newPage();
await loginApi(newPage);
await newPage.goto(`${baseURL}${ROUTES.APPLICATION}`);
page = newPage;
});
test('Should have a valid route', async () => {
await page.goto(ROUTES.ALL_ERROR);
await expect(page).toHaveURL(ROUTES.ALL_ERROR);
expect(await page.screenshot()).toMatchSnapshot();
});
test('Should have a valid Breadcrumbs', async () => {
await page.goto(ROUTES.ALL_ERROR, {
waitUntil: 'networkidle',
});
const expectionsLocator = page.locator('a:has-text("Exceptions")');
await expect(expectionsLocator).toBeVisible();
await expect(expectionsLocator).toHaveText('Exceptions');
await expect(expectionsLocator).toHaveAttribute('href', ROUTES.ALL_ERROR);
expect(await page.screenshot()).toMatchSnapshot();
});
test('Should render the page with 404 status', async () => {
await page.route('**listErrors', (route) =>
route.fulfill({
status: 404,
contentType: JsonApplicationType,
body: JSON.stringify([]),
}),
);
await page.goto(ROUTES.ALL_ERROR, {
waitUntil: 'networkidle',
});
await noDataTableData(page);
expect(await page.screenshot()).toMatchSnapshot();
});
test('Should render the page with 500 status in antd notification with no data antd table', async () => {
await page.route(`**/listErrors**`, (route) =>
route.fulfill({
status: 500,
contentType: JsonApplicationType,
body: JSON.stringify([]),
}),
);
await page.goto(ROUTES.ALL_ERROR, {
waitUntil: 'networkidle',
});
const text = 'Something went wrong';
const el = page.locator(`text=${text}`);
expect(el).toBeVisible();
expect(el).toHaveText(`${text}`);
expect(await el.getAttribute('disabled')).toBe(null);
await noDataTableData(page);
expect(await page.screenshot()).toMatchSnapshot();
});
test('Should render data in antd table', async () => {
await Promise.all([
page.route(`**/listErrors**`, (route) =>
route.fulfill({
status: 200,
contentType: JsonApplicationType,
body: JSON.stringify(successAllErrors),
}),
),
page.route('**/countErrors**', (route) =>
route.fulfill({
status: 200,
contentType: JsonApplicationType,
body: JSON.stringify(200),
}),
),
]);
await page.goto(ROUTES.ALL_ERROR, {
waitUntil: 'networkidle',
});
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
const expectionType = page.locator(
`td:has-text("${successAllErrors[1].exceptionType}")`,
);
expect(expectionType).toBeVisible();
const second = page.locator('li > a:has-text("2") >> nth=0');
const isVisisble = await second.isVisible();
expect(isVisisble).toBe(true);
expect(await page.screenshot()).toMatchSnapshot();
});
});

View File

@ -1,92 +0,0 @@
[
{
"exceptionType": "ConnectionError",
"exceptionMessage": "HTTPSConnectionPool(host='run.mocekdy.io', port=443): Max retries exceeded with url: /v3/1cwb67153-a6ac-4aae-aca6-273ed68b5d9e (Caused by NewConnectionError('\u003curllib3.connection.HTTPSConnection object at 0x108ce9c10\u003e: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))",
"exceptionCount": 2,
"lastSeen": "2022-07-14T10:29:48.955274Z",
"firstSeen": "2022-07-14T10:29:48.950721Z",
"serviceName": "1rfflaskAp",
"groupID": "e24d35bda98c5499a5c8df3ba61b0238"
},
{
"exceptionType": "NameError",
"exceptionMessage": "name 'listf' is not defined",
"exceptionCount": 8,
"lastSeen": "2022-07-14T10:30:42.411035Z",
"firstSeen": "2022-07-14T10:29:45.426784Z",
"serviceName": "1rfflaskAp",
"groupID": "efc46adcd5e87b65f8f244cba683b265"
},
{
"exceptionType": "ZeroDivisionError",
"exceptionMessage": "division by zero",
"exceptionCount": 1,
"lastSeen": "2022-07-14T10:29:54.195996Z",
"firstSeen": "2022-07-14T10:29:54.195996Z",
"serviceName": "1rfflaskAp",
"groupID": "a49058b540eef9aefe159d84f1a2b6df"
},
{
"exceptionType": "MaxRetryError",
"exceptionMessage": "HTTPSConnectionPool(host='rufn.fmoceky.io', port=443): Max retries exceeded with url: /v3/b851a5c6-ab54-495a-be04-69834ae0d2a7 (Caused by NewConnectionError('\u003curllib3.connection.HTTPSConnection object at 0x108ec2640\u003e: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))",
"exceptionCount": 1,
"lastSeen": "2022-07-14T10:29:49.471402Z",
"firstSeen": "2022-07-14T10:29:49.471402Z",
"serviceName": "1rfflaskAp",
"groupID": "e59d39239f4d48842d83e3cc4cf53249"
},
{
"exceptionType": "MaxRetryError",
"exceptionMessage": "HTTPSConnectionPool(host='run.mocekdy.io', port=443): Max retries exceeded with url: /v3/1cwb67153-a6ac-4aae-aca6-273ed68b5d9e (Caused by NewConnectionError('\u003curllib3.connection.HTTPSConnection object at 0x108ce9c10\u003e: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))",
"exceptionCount": 1,
"lastSeen": "2022-07-14T10:29:48.947579Z",
"firstSeen": "2022-07-14T10:29:48.947579Z",
"serviceName": "1rfflaskAp",
"groupID": "14d18a6fb1cd3f541de1566530e75486"
},
{
"exceptionType": "ConnectionError",
"exceptionMessage": "HTTPSConnectionPool(host='rufn.fmoceky.io', port=443): Max retries exceeded with url: /v3/b851a5c6-ab54-495a-be04-69834ae0d2a7 (Caused by NewConnectionError('\u003curllib3.connection.HTTPSConnection object at 0x108ec2640\u003e: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))",
"exceptionCount": 2,
"lastSeen": "2022-07-14T10:29:49.476718Z",
"firstSeen": "2022-07-14T10:29:49.472271Z",
"serviceName": "1rfflaskAp",
"groupID": "bf6d88d10397ca3194b96a10f4719031"
},
{
"exceptionType": "github.com/gin-gonic/gin.Error",
"exceptionMessage": "Sample Error",
"exceptionCount": 6,
"lastSeen": "2022-07-15T18:55:32.3538096Z",
"firstSeen": "2022-07-14T14:47:19.874387Z",
"serviceName": "goApp",
"groupID": "b4fd099280072d45318e1523d82aa9c1"
},
{
"exceptionType": "MaxRetryError",
"exceptionMessage": "HTTPSConnectionPool(host='rufn.fmoceky.io', port=443): Max retries exceeded with url: /v3/b851a5c6-ab54-495a-be04-69834ae0d2a7 (Caused by NewConnectionError('\u003curllib3.connection.HTTPSConnection object at 0x10801b490\u003e: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))",
"exceptionCount": 1,
"lastSeen": "2022-07-14T11:07:06.560593Z",
"firstSeen": "2022-07-14T11:07:06.560593Z",
"serviceName": "samplFlaskApp",
"groupID": "1945671c945b10641e73b0fe28c4d486"
},
{
"exceptionType": "ConnectionError",
"exceptionMessage": "HTTPSConnectionPool(host='rufn.fmoceky.io', port=443): Max retries exceeded with url: /v3/b851a5c6-ab54-495a-be04-69834ae0d2a7 (Caused by NewConnectionError('\u003curllib3.connection.HTTPSConnection object at 0x10801b490\u003e: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))",
"exceptionCount": 2,
"lastSeen": "2022-07-14T11:07:06.56493Z",
"firstSeen": "2022-07-14T11:07:06.561074Z",
"serviceName": "samplFlaskApp",
"groupID": "5bea5295cac187404005f9c96e71aa53"
},
{
"exceptionType": "ConnectionError",
"exceptionMessage": "HTTPSConnectionPool(host='rufn.fmoceky.io', port=443): Max retries exceeded with url: /v3/b851a5c6-ab54-495a-be04-69834ae0d2a7 (Caused by NewConnectionError('\u003curllib3.connection.HTTPSConnection object at 0x108031820\u003e: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))",
"exceptionCount": 2,
"lastSeen": "2022-07-14T11:07:06.363977Z",
"firstSeen": "2022-07-14T11:07:06.361163Z",
"serviceName": "samplFlaskApp",
"groupID": "52a1fbe033453d806c0f24ba39168a78"
}
]

View File

@ -1,16 +0,0 @@
{
"status": "success",
"data": {
"id": 219,
"uuid": "d697fddb-a771-4bb4-aa38-810f000ed96a",
"created_at": "2023-11-17T18:36:36.185916891Z",
"created_by": "vikrant@signoz.io",
"updated_at": "2023-11-17T18:36:36.185916989Z",
"updated_by": "vikrant@signoz.io",
"data": {
"title": "Sample Title",
"uploadedGrafana": false
},
"isLocked": null
}
}

View File

@ -1,91 +0,0 @@
{
"status": "success",
"data": {
"id": 219,
"uuid": "d697fddb-a771-4bb4-aa38-810f000ed96a",
"created_at": "2023-11-17T20:44:03.167646604Z",
"created_by": "vikrant@signoz.io",
"updated_at": "2023-11-17T20:51:23.058536475Z",
"updated_by": "vikrant@signoz.io",
"data": {
"description": "Playwright Dashboard T",
"layout": [
{
"h": 3,
"i": "9fbcf0db-1572-4572-bf6b-0a84dd10ed85",
"w": 6,
"x": 0,
"y": 0
}
],
"name": "",
"tags": [],
"title": "Playwright Dashboard",
"variables": {},
"widgets": [
{
"description": "",
"id": "9fbcf0db-1572-4572-bf6b-0a84dd10ed85",
"isStacked": false,
"nullZeroValues": "",
"opacity": "",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "",
"id": "------",
"isColumn": false,
"isJSON": false,
"key": "",
"type": ""
},
"aggregateOperator": "count",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [],
"op": "AND"
},
"groupBy": [],
"having": [],
"legend": "",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"stepInterval": 60
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "6b4011e4-bcea-497d-81a9-0ee7816b679d",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"timePreferance": "GLOBAL_TIME",
"title": "Time1"
}
]
},
"isLocked": 0
}
}

View File

@ -1,4 +0,0 @@
{
"status": "success",
"data": []
}

View File

@ -1,16 +0,0 @@
{
"status": "success",
"data": {
"id": 219,
"uuid": "d697fddb-a771-4bb4-aa38-810f000ed96a",
"created_at": "2023-11-17T18:36:36.185916891Z",
"created_by": "vikrant@signoz.io",
"updated_at": "2023-11-17T18:36:36.185916989Z",
"updated_by": "vikrant@signoz.io",
"data": {
"title": "Sample Title",
"uploadedGrafana": false
},
"isLocked": 0
}
}

View File

@ -1,91 +0,0 @@
{
"status": "success",
"data": {
"id": 219,
"uuid": "d697fddb-a771-4bb4-aa38-810f000ed96a",
"created_at": "2023-11-17T20:44:03.167646604Z",
"created_by": "vikrant@signoz.io",
"updated_at": "2023-11-17T20:51:23.058536475Z",
"updated_by": "vikrant@signoz.io",
"data": {
"description": "Playwright Dashboard T",
"layout": [
{
"h": 3,
"i": "9fbcf0db-1572-4572-bf6b-0a84dd10ed85",
"w": 6,
"x": 0,
"y": 0
}
],
"name": "",
"tags": [],
"title": "Playwright Dashboard",
"variables": {},
"widgets": [
{
"description": "",
"id": "9fbcf0db-1572-4572-bf6b-0a84dd10ed85",
"isStacked": false,
"nullZeroValues": "",
"opacity": "",
"panelTypes": "graph",
"query": {
"builder": {
"queryData": [
{
"aggregateAttribute": {
"dataType": "",
"id": "------",
"isColumn": false,
"isJSON": false,
"key": "",
"type": ""
},
"aggregateOperator": "count",
"dataSource": "metrics",
"disabled": false,
"expression": "A",
"filters": {
"items": [],
"op": "AND"
},
"groupBy": [],
"having": [],
"legend": "",
"limit": null,
"orderBy": [],
"queryName": "A",
"reduceTo": "avg",
"stepInterval": 60
}
],
"queryFormulas": []
},
"clickhouse_sql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"id": "6b4011e4-bcea-497d-81a9-0ee7816b679d",
"promql": [
{
"disabled": false,
"legend": "",
"name": "A",
"query": ""
}
],
"queryType": "builder"
},
"timePreferance": "GLOBAL_TIME",
"title": ""
}
]
},
"isLocked": 0
}
}

View File

@ -1,18 +0,0 @@
{
"status": "success",
"data": {
"id": 219,
"uuid": "d697fddb-a771-4bb4-aa38-810f000ed96a",
"created_at": "2023-11-17T18:47:15.740385406Z",
"created_by": "vikrant@signoz.io",
"updated_at": "2023-11-17T19:11:25.052190048Z",
"updated_by": "vikrant@signoz.io",
"data": {
"description": "Playwright Dashboard Description",
"tags": [],
"title": "Playwright Dashboard",
"uploadedGrafana": false
},
"isLocked": 0
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,5 +0,0 @@
{
"error": "Error/Exception not found",
"errorType": "not_found",
"status": "error"
}

View File

@ -1,7 +0,0 @@
{
"nextErrorID": "",
"nextTimestamp": "0001-01-01T00:00:00Z",
"prevErrorID": "217133e5f7df429abd31b507859ea513",
"prevTimestamp": "2022-07-14T10:29:48.950721Z",
"groupID": "e24d35bda98c5499a5c8df3ba61b0238"
}

View File

@ -1,7 +0,0 @@
{
"accessJwt": "authtoken",
"accessJwtExpiry": 1656609177,
"refreshJwt": "refreshJwt",
"refreshJwtExpiry": 1659199377,
"userId": "34917776-514b-4b95-a4f5-1a5cc06e34b6"
}

View File

@ -1,3 +0,0 @@
{
"data": "org updated successfully"
}

View File

@ -1 +0,0 @@
{ "data": "user registered successfully" }

View File

@ -1,5 +0,0 @@
{
"status": "error",
"errorType": "unauthorized",
"error": "You are not allowed to create an account. Please ask your admin to send an invite link"
}

View File

@ -1,68 +0,0 @@
[
{
"serviceName": "redis",
"p99": 35396180,
"avgDuration": 15149389.806977473,
"numCalls": 22329,
"callRate": 12.615254237288136,
"numErrors": 4135,
"errorRate": 18.51851851851852,
"num4XX": 0,
"fourXXRate": 0
},
{
"serviceName": "frontend",
"p99": 1173509510.0000002,
"avgDuration": 747007254.5344619,
"numCalls": 1654,
"callRate": 0.9344632768361582,
"numErrors": 0,
"errorRate": 0,
"num4XX": 0,
"fourXXRate": 0
},
{
"serviceName": "mysql",
"p99": 776834620,
"avgDuration": 349280732.76904476,
"numCalls": 1654,
"callRate": 0.9344632768361582,
"numErrors": 0,
"errorRate": 0,
"num4XX": 0,
"fourXXRate": 0
},
{
"serviceName": "customer",
"p99": 776995390,
"avgDuration": 349451783.5550181,
"numCalls": 1654,
"callRate": 0.9344632768361582,
"numErrors": 0,
"errorRate": 0,
"num4XX": 0,
"fourXXRate": 0
},
{
"serviceName": "route",
"p99": 79617600.00000001,
"avgDuration": 50698870.85852479,
"numCalls": 16540,
"callRate": 9.344632768361581,
"numErrors": 0,
"errorRate": 0,
"num4XX": 0,
"fourXXRate": 0
},
{
"serviceName": "driver",
"p99": 241056990,
"avgDuration": 204975300.48367593,
"numCalls": 1654,
"callRate": 0.9344632768361582,
"numErrors": 0,
"errorRate": 0,
"num4XX": 0,
"fourXXRate": 0
}
]

View File

@ -1,14 +0,0 @@
{
"status": "success",
"data": {
"attributeKeys": [
{
"key": "serviceName",
"dataType": "string",
"type": "tag",
"isColumn": true,
"isJSON": false
}
]
}
}

View File

@ -1,14 +0,0 @@
{
"status": "success",
"data": {
"attributeKeys": [
{
"key": "durationNano",
"dataType": "float64",
"type": "tag",
"isColumn": true,
"isJSON": false
}
]
}
}

View File

@ -1,21 +0,0 @@
{
"status": "success",
"data": {
"attributeKeys": [
{
"key": "externalHttpMethod",
"dataType": "string",
"type": "tag",
"isColumn": true,
"isJSON": false
},
{
"key": "httpMethod",
"dataType": "string",
"type": "tag",
"isColumn": true,
"isJSON": false
}
]
}
}

View File

@ -1,56 +0,0 @@
{
"status": "success",
"data": {
"attributeKeys": [
{
"key": "dbName",
"dataType": "string",
"type": "tag",
"isColumn": true,
"isJSON": false
},
{
"key": "host.name",
"dataType": "string",
"type": "resource",
"isColumn": false,
"isJSON": false
},
{
"key": "process.runtime.name",
"dataType": "string",
"type": "resource",
"isColumn": false,
"isJSON": false
},
{
"key": "service.name",
"dataType": "string",
"type": "resource",
"isColumn": false,
"isJSON": false
},
{
"key": "serviceName",
"dataType": "string",
"type": "tag",
"isColumn": true,
"isJSON": false
},
{
"key": "name",
"dataType": "string",
"type": "tag",
"isColumn": true,
"isJSON": false
},
{
"key": "telemetry.sdk.name",
"dataType": "string",
"type": "resource",
"isColumn": false,
"isJSON": false
}
]
}
}

View File

@ -1,14 +0,0 @@
{
"status": "success",
"data": {
"attributeKeys": [
{
"key": "responseStatusCode",
"dataType": "string",
"type": "tag",
"isColumn": true,
"isJSON": false
}
]
}
}

View File

@ -1,14 +0,0 @@
{
"status": "success",
"data": {
"attributeKeys": [
{
"key": "serviceName",
"dataType": "string",
"type": "tag",
"isColumn": true,
"isJSON": false
}
]
}
}

View File

@ -1,26 +0,0 @@
{
"status": "success",
"data": {
"resultType": "",
"result": [
{
"queryName": "A",
"series": null,
"list": [
{
"timestamp": "2023-11-14T18:26:59.966905Z",
"data": {
"durationNano": 57896000,
"httpMethod": "GET",
"name": "HTTP GET /route",
"responseStatusCode": "200",
"serviceName": "route",
"spanID": "0e5da5411ccc8ea5",
"traceID": "00000000000000007008a05a3d9e5b97"
}
}
]
}
]
}
}

View File

@ -1,4 +0,0 @@
{
"status": "success",
"data": "336368a4-dba7-4d65-9f91-142a355edb23"
}

View File

@ -1,52 +0,0 @@
{
"status": "success",
"data": [
{
"uuid": "8402eda3-2be3-4e07-930b-9ff69c3da34f",
"name": "PlayWright",
"category": "",
"createdAt": "2023-11-16T19:24:49.875396768Z",
"createdBy": "contributors@signoz.io",
"updatedAt": "2023-11-16T19:24:49.875396872Z",
"updatedBy": "contributors@signoz.io",
"sourcePage": "traces",
"tags": [""],
"compositeQuery": {
"builderQueries": {
"A": {
"queryName": "A",
"stepInterval": 60,
"dataSource": "traces",
"aggregateOperator": "count",
"aggregateAttribute": {
"key": "",
"dataType": "",
"type": "",
"isColumn": false,
"isJSON": false
},
"filters": {
"op": "AND",
"items": []
},
"expression": "A",
"disabled": false,
"limit": 0,
"offset": 0,
"pageSize": 0,
"orderBy": [
{
"columnName": "timestamp",
"order": "desc"
}
],
"reduceTo": "avg"
}
},
"panelType": "table",
"queryType": "builder"
},
"extraData": ""
}
]
}

View File

@ -1,24 +0,0 @@
{
"status": "success",
"data": {
"resultType": "",
"result": [
{
"queryName": "A",
"series": null,
"list": [
{
"timestamp": "0001-01-01T00:00:00Z",
"data": {
"span_count": 51,
"subQuery.durationNano": 1533445000,
"subQuery.name": "HTTP GET /dispatch",
"subQuery.serviceName": "frontend",
"traceID": "0000000000000000013e51e33c929173"
}
}
]
}
]
}
}

View File

@ -1,24 +0,0 @@
{
"status": "success",
"data": {
"resultType": "",
"result": [
{
"queryName": "A",
"series": [
{
"labels": {},
"labelsArray": null,
"values": [
{
"timestamp": 1700161420000,
"value": "85784"
}
]
}
],
"list": null
}
]
}
}

View File

@ -1,11 +0,0 @@
{
"createdAt": 1651759141,
"email": "prashant@signoz.io",
"groupId": "36261238-3214-4ae9-9ef1-661a9f7be5d0",
"id": "509fab4a-2578-4f24-8245-1b77b2d6d937",
"name": "Prashant",
"orgId": "72b4024a-3301-4d90-951e-ee071b96dba5",
"organization": "Meta",
"profilePictureURL": "",
"role": "ADMIN"
}

View File

@ -1,43 +0,0 @@
import { Page } from '@playwright/test';
import { getVersion } from 'constants/api';
import loginApiResponse from './api/login/200.json';
import updateOrgResponse from './api/organisation/201.json';
import successLoginResponse from './api/register/200.json';
import userLoginResponse from './api/userId/200.json';
import { version } from './constant';
export const waitForVersionApiSuccess = async (page: Page): Promise<void> => {
await page.route(`**/${getVersion}`, (route) =>
route.fulfill({
status: 200,
body: JSON.stringify({ version }),
}),
);
};
export const loginApi = async (page: Page): Promise<void> => {
await Promise.all([
page.route(`**/register`, (route) =>
route.fulfill({
status: 200,
body: JSON.stringify(successLoginResponse),
}),
),
page.route(`**/user/${loginApiResponse.userId}`, (route) =>
route.fulfill({ status: 200, body: JSON.stringify(userLoginResponse) }),
),
page.route('**/login', (route) =>
route.fulfill({
status: 200,
body: JSON.stringify(loginApiResponse),
}),
),
page.route(`**/orgs/me`, (route) =>
route.fulfill({
status: 200,
body: JSON.stringify(updateOrgResponse),
}),
),
]);
};

View File

@ -1,10 +0,0 @@
export const version = 'v1.0.0';
export const validemail = 'sample@signoz.io';
export const validName = 'Palash';
export const validCompanyName = 'Signoz';
export const validPassword = 'SamplePassword98@@';
export const getStartedButtonSelector = 'button[data-attr="signup"]';
export const confirmPasswordSelector = '#password-confirm-error';
export const JsonApplicationType = 'application/json';

View File

@ -1,29 +0,0 @@
import { expect, test } from '@playwright/test';
import { getVersion } from 'constants/api';
import ROUTES from 'constants/routes';
test.describe('Version API fail while loading login page', async () => {
test('Something went wrong', async ({ page, baseURL }) => {
const loginPage = `${baseURL}${ROUTES.LOGIN}`;
const text = 'Something went wrong';
await page.route(`**/${getVersion}`, (route) =>
route.fulfill({
status: 500,
body: JSON.stringify({ error: text }),
}),
);
await page.goto(loginPage, {
waitUntil: 'networkidle',
});
const el = page.locator(`text=${text}`);
expect(el).toBeVisible();
expect(el).toHaveText(`${text}`);
expect(await el.getAttribute('disabled')).toBe(null);
expect(await page.screenshot()).toMatchSnapshot();
});
});

View File

@ -1,50 +0,0 @@
import { expect, test } from '@playwright/test';
import ROUTES from 'constants/routes';
import { waitForVersionApiSuccess } from '../fixtures/common';
import { version } from '../fixtures/constant';
test.describe('Login Page', () => {
test.beforeEach(async ({ baseURL, page }) => {
const loginPage = `${baseURL}${ROUTES.LOGIN}`;
await waitForVersionApiSuccess(page);
await Promise.all([page.goto(loginPage), page.waitForRequest('**/version')]);
});
test('Login Page text should be visible', async ({ page }) => {
const signup = 'Monitor your applications. Find what is causing issues.';
// Click text=Monitor your applications. Find what is causing issues.
const el = page.locator(`text=${signup}`);
expect(el).toBeVisible();
});
test('Create an account button should be present', async ({
page,
baseURL,
}) => {
const loginPage = `${baseURL}${ROUTES.LOGIN}`;
// find button which has text=Create an account
const button = page.locator('text=Create an account');
expect(button).toBeVisible();
expect(button).toHaveText('Create an account');
expect(await button.getAttribute('disabled')).toBe(null);
expect(await button.isEnabled()).toBe(true);
await expect(page).toHaveURL(loginPage);
});
test('Version of the application when api returns 200', async ({ page }) => {
// Click text=SigNoz ${version}
const element = page.locator(`text=SigNoz ${version}`);
element.isVisible();
const text = await element.innerText();
expect(text).toBe(`SigNoz ${version}`);
expect(await page.screenshot()).toMatchSnapshot();
});
});

View File

@ -1,32 +0,0 @@
import { expect, Page, test } from '@playwright/test';
import ROUTES from 'constants/routes';
import { loginApi } from '../fixtures/common';
let page: Page;
test.describe('Service Page', () => {
test.beforeEach(async ({ baseURL, browser }) => {
const context = await browser.newContext({ storageState: 'tests/auth.json' });
const newPage = await context.newPage();
await loginApi(newPage);
await newPage.goto(`${baseURL}${ROUTES.APPLICATION}`);
page = newPage;
});
test('Serice Page is rendered', async ({ baseURL }) => {
await expect(page).toHaveURL(`${baseURL}${ROUTES.APPLICATION}`);
expect(await page.screenshot()).toMatchSnapshot();
});
test('Logged In must be true', async () => {
const { app } = await page.evaluate(() => window.store.getState());
const { isLoggedIn } = app;
expect(isLoggedIn).toBe(true);
});
});

View File

@ -1,150 +0,0 @@
import { expect, Page, test } from '@playwright/test';
import ROUTES from 'constants/routes';
import servicesSuccessResponse from '../fixtures/api/services/200.json';
import { loginApi } from '../fixtures/common';
import { SERVICE_TABLE_HEADERS } from './utils';
let page: Page;
test.describe('Service flow', () => {
test.beforeEach(async ({ baseURL, browser }) => {
const context = await browser.newContext({ storageState: 'tests/auth.json' });
const newPage = await context.newPage();
await loginApi(newPage);
await newPage.goto(`${baseURL}${ROUTES.APPLICATION}`);
page = newPage;
});
test('Services empty page', async ({ baseURL }) => {
// visit services page
await page.goto(`${baseURL}${ROUTES.APPLICATION}`);
await page.route(`**/services`, (route) =>
route.fulfill({
status: 200,
json: [],
}),
);
// expect noData to be present
await expect(page.getByText('No data')).toBeVisible();
});
test('Services table and service details page rendered with correct data', async ({
baseURL,
}) => {
// visit services page
await page.goto(`${baseURL}${ROUTES.APPLICATION}`);
// assert the URL of the services page
await expect(page).toHaveURL(`${baseURL}${ROUTES.APPLICATION}`);
// mock the services list call to return non-empty data
await page.route(`**/services`, (route) =>
route.fulfill({
status: 200,
json: servicesSuccessResponse,
}),
);
// assert the presence of services breadcrumbs
const breadcrumbServicesText = await page
.locator('.ant-breadcrumb-link a[href="/services"]')
.nth(1)
.textContent();
await expect(breadcrumbServicesText).toEqual('Services');
// expect the services headers to be loaded correctly
const p99Latency = page.locator(
`th:has-text("${SERVICE_TABLE_HEADERS.P99LATENCY}")`,
);
await expect(p99Latency).toBeVisible();
const errorRate = await page.locator(
`th:has-text("${SERVICE_TABLE_HEADERS.ERROR_RATE}")`,
);
await expect(errorRate).toBeVisible();
const operationsPerSecond = await page.locator(
`th:has-text("${SERVICE_TABLE_HEADERS.OPS_PER_SECOND}")`,
);
await expect(operationsPerSecond).toBeVisible();
// expect services to be listed in the table
const redisService = await page
.locator('a[href="/services/redis"]')
.isVisible();
expect(redisService).toBeTruthy();
// route to a service details page
await page.locator('a[href="/services/redis"]').click();
// wait for the network calls to be settled
await page.waitForLoadState('networkidle');
// render the overview tab
await page.getByRole('tab', { name: 'Overview' }).click();
// check the presence of different graphs on the overview tab
const latencyGraph = await page
.locator('[data-testid="service_latency"]')
.isVisible();
expect(latencyGraph).toBeTruthy();
const rateOps = await page
.locator('[data-testid="operations_per_sec"]')
.isVisible();
expect(rateOps).toBeTruthy();
const errorPercentage = await page
.locator('[data-testid="error_percentage_%"]')
.isVisible();
expect(errorPercentage).toBeTruthy();
// navigate to the DB call metrics and validate the tables
await page.getByRole('tab', { name: 'DB Call Metrics' }).click();
const databaseCallRps = await page
.locator('[data-testid="database_call_rps"]')
.isVisible();
expect(databaseCallRps).toBeTruthy();
const databaseCallsAvgDuration = await page
.locator('[data-testid="database_call_avg_duration"]')
.isVisible();
expect(databaseCallsAvgDuration).toBeTruthy();
// navigate to external metrics and validate the tables
await page.getByRole('tab', { name: 'External Metrics' }).click();
const externalCallErrorPerc = await page
.locator('[data-testid="external_call_error_percentage"]')
.isVisible();
expect(externalCallErrorPerc).toBeTruthy();
const externalCallDuration = await page
.locator('[data-testid="external_call_duration"]')
.isVisible();
expect(externalCallDuration).toBeTruthy();
const externalCallRps = await page
.locator('[data-testid="external_call_rps_by_address"]')
.isVisible();
expect(externalCallRps).toBeTruthy();
const externalCallDurationByAddress = await page
.locator('[data-testid="external_call_duration_by_address"]')
.isVisible();
expect(externalCallDurationByAddress).toBeTruthy();
});
});

View File

@ -1,6 +0,0 @@
export const SERVICE_TABLE_HEADERS = {
APPLICATION: 'Applicaton',
P99LATENCY: 'P99 latency (in ms)',
ERROR_RATE: 'Error Rate (% of total)',
OPS_PER_SECOND: 'Operations Per Second',
};

View File

@ -1,232 +0,0 @@
import { expect, Page, PlaywrightTestOptions, test } from '@playwright/test';
import ROUTES from 'constants/routes';
import { loginApi, waitForVersionApiSuccess } from '../fixtures/common';
import {
confirmPasswordSelector,
getStartedButtonSelector,
validCompanyName,
validemail,
validName,
validPassword,
} from '../fixtures/constant';
const waitForSignUpPageSuccess = async (
baseURL: PlaywrightTestOptions['baseURL'],
page: Page,
): Promise<void> => {
const signupPage = `${baseURL}${ROUTES.SIGN_UP}`;
await page.goto(signupPage);
await waitForVersionApiSuccess(page);
};
interface FillDetailsInSignUpFormProps {
page: Page;
email: string;
name: string;
companyName: string;
password: string;
confirmPassword: string;
}
const fillDetailsInSignUpForm = async ({
page,
email,
name,
companyName,
password,
confirmPassword,
}: FillDetailsInSignUpFormProps): Promise<void> => {
const emailplaceholder = '[placeholder="name\\@yourcompany\\.com"]';
const nameplaceholder = '[placeholder="Your Name"]';
const companyPlaceholder = '[placeholder="Your Company"]';
const currentPasswordId = '#currentPassword';
const confirmPasswordId = '#confirmPassword';
// Fill [placeholder="name\@yourcompany\.com"]
await page.locator(emailplaceholder).fill(email);
// Fill [placeholder="Your Name"]
await page.locator(nameplaceholder).fill(name);
// Fill [placeholder="Your Company"]
await page.locator(companyPlaceholder).fill(companyName);
// Fill #currentPassword
await page.locator(currentPasswordId).fill(password);
// Fill #confirmPasswordId
await page.locator(confirmPasswordId).fill(confirmPassword);
};
test.describe('Sign Up Page', () => {
test('When User successfull signup and logged in, he should be redirected to dashboard', async ({
page,
baseURL,
}) => {
const loginPage = `${baseURL}${ROUTES.LOGIN}`;
await waitForVersionApiSuccess(page);
await Promise.all([page.goto(loginPage), page.waitForRequest('**/version')]);
const buttonSignupButton = page.locator('text=Create an account');
await buttonSignupButton.click();
expect(page).toHaveURL(`${baseURL}${ROUTES.SIGN_UP}`);
expect(await page.screenshot()).toMatchSnapshot();
});
test('Invite link validation', async ({ baseURL, page }) => {
await waitForSignUpPageSuccess(baseURL, page);
const message =
'This will create an admin account. If you are not an admin, please ask your admin for an invite link';
const messageText = await page.locator(`text=${message}`).innerText();
expect(messageText).toBe(message);
expect(await page.screenshot()).toMatchSnapshot();
});
test('User Sign up with valid details', async ({ baseURL, page, context }) => {
await waitForSignUpPageSuccess(baseURL, page);
const gettingStartedButton = page.locator(getStartedButtonSelector);
expect(await gettingStartedButton.isDisabled()).toBe(true);
await fillDetailsInSignUpForm({
companyName: validCompanyName,
confirmPassword: validPassword,
email: validemail,
name: validName,
page,
password: validPassword,
});
// password validation message is not present
const locator = await page.locator(confirmPasswordSelector).isVisible();
expect(locator).toBe(false);
const buttonText = await gettingStartedButton.evaluate((e) => e.innerHTML);
expect(buttonText).toMatch(/Get Started/i);
// Getting Started button is not disabled
expect(await gettingStartedButton.isDisabled()).toBe(false);
await loginApi(page);
await gettingStartedButton.click();
await expect(page).toHaveURL(`${baseURL}${ROUTES.APPLICATION}`);
await context.storageState({
path: 'tests/auth.json',
});
expect(await page.screenshot()).toMatchSnapshot();
});
test('Empty name with valid details', async ({ baseURL, page }) => {
await waitForSignUpPageSuccess(baseURL, page);
await fillDetailsInSignUpForm({
companyName: validCompanyName,
confirmPassword: validPassword,
email: validemail,
name: '',
page,
password: validPassword,
});
const gettingStartedButton = page.locator(getStartedButtonSelector);
expect(await gettingStartedButton.isDisabled()).toBe(true);
expect(await page.screenshot()).toMatchSnapshot();
});
test('Empty Company name with valid details', async ({ baseURL, page }) => {
await waitForSignUpPageSuccess(baseURL, page);
await fillDetailsInSignUpForm({
companyName: '',
confirmPassword: validPassword,
email: validemail,
name: validName,
page,
password: validPassword,
});
const gettingStartedButton = page.locator(getStartedButtonSelector);
expect(await gettingStartedButton.isDisabled()).toBe(true);
expect(await page.screenshot()).toMatchSnapshot();
});
test('Empty Email with valid details', async ({ baseURL, page }) => {
await waitForSignUpPageSuccess(baseURL, page);
await fillDetailsInSignUpForm({
companyName: validCompanyName,
confirmPassword: validPassword,
email: '',
name: validName,
page,
password: validPassword,
});
const gettingStartedButton = page.locator(getStartedButtonSelector);
expect(await gettingStartedButton.isDisabled()).toBe(true);
expect(await page.screenshot()).toMatchSnapshot();
});
test('Empty Password and confirm password with valid details', async ({
baseURL,
page,
}) => {
await waitForSignUpPageSuccess(baseURL, page);
await fillDetailsInSignUpForm({
companyName: validCompanyName,
confirmPassword: '',
email: validemail,
name: validName,
page,
password: '',
});
const gettingStartedButton = page.locator(getStartedButtonSelector);
expect(await gettingStartedButton.isDisabled()).toBe(true);
// password validation message is not present
const locator = await page.locator(confirmPasswordSelector).isVisible();
expect(locator).toBe(false);
expect(await page.screenshot()).toMatchSnapshot();
});
test('Miss Match Password and confirm password with valid details', async ({
baseURL,
page,
}) => {
await waitForSignUpPageSuccess(baseURL, page);
await fillDetailsInSignUpForm({
companyName: validCompanyName,
confirmPassword: validPassword,
email: validemail,
name: validName,
page,
password: '',
});
// password validation message is not present
const locator = await page.locator(confirmPasswordSelector).isVisible();
expect(locator).toBe(true);
expect(await page.screenshot()).toMatchSnapshot();
});
});

View File

@ -1,118 +0,0 @@
import { Page, test, expect } from '@playwright/test';
import { loginApi } from '../fixtures/common';
import ROUTES from 'constants/routes';
import queryRangeSuccessResponse from '../fixtures/api/traces/queryRange200.json';
import tracesSuccessResponse from '../fixtures/api/traces/tracesRange200.json';
import tracesTableSuccessResponse from '../fixtures/api/traces/tracesTableView200.json';
import {
defaultAttributeKeysData,
httpMethodAttributeID,
newExplorerCtaID,
queryRangeApiEndpoint,
saveNewViewID,
saveNewViewWithNameID,
serviceAttributeID,
tableViewTabID,
traceExplorerViewsGetEndpoint,
traceExplorerViewsPostEndpoint,
traceRowTraceTabID,
traceTabID,
tracesExplorerQueryData,
tracesExplorerViewsData,
tracesExplorerViewsPostData,
} from './utils';
let page: Page;
test.describe('New Traces Explorer', () => {
test.beforeEach(async ({ baseURL, browser }) => {
const context = await browser.newContext({
storageState: 'tests/auth.json',
});
const newPage = await context.newPage();
await loginApi(newPage);
await newPage.goto(`${baseURL}${ROUTES.APPLICATION}`);
page = newPage;
});
test('Traces Explorer Tests', async ({}) => {
await page.locator(`li[data-menu-id*="/trace"]`).click();
await tracesExplorerQueryData(page, queryRangeSuccessResponse);
await defaultAttributeKeysData(page);
const queryRangeRequest = page.waitForRequest(`**/${queryRangeApiEndpoint}`);
await page.locator(`data-testid=${newExplorerCtaID}`).click();
await queryRangeRequest;
await page.getByText('List View').click();
const serviceName = await page
.locator(`data-testid=${serviceAttributeID}`)
.textContent();
expect(serviceName).toBe('route');
const httpMethod = await page
.locator(`data-testid=${httpMethodAttributeID}`)
.textContent();
expect(httpMethod).toBe('GET');
await tracesExplorerQueryData(page, tracesSuccessResponse);
await page.locator(`id=${traceTabID}`).click();
const traceID = await page
.locator(`data-testid=${traceRowTraceTabID}`)
.textContent();
expect(traceID).toBe(
tracesSuccessResponse.data.result[0].list[0].data.traceID,
);
await tracesExplorerQueryData(page, tracesTableSuccessResponse);
await page.locator(`id=${tableViewTabID}`).click();
await page.waitForLoadState('networkidle');
const count = await page.getByText('85784').isVisible();
await expect(count).toBeTruthy();
await page.locator(`data-testid=${saveNewViewID}`).click();
await page.locator('id=viewName').type('Playwright');
await tracesExplorerQueryData(page, queryRangeSuccessResponse);
await tracesExplorerViewsData(page);
await tracesExplorerViewsPostData(page);
const viewsSaveRequest = page.waitForRequest(
`**/${traceExplorerViewsPostEndpoint}`,
);
const viewsGetRequest = page.waitForRequest(
`**/${traceExplorerViewsGetEndpoint}`,
);
await page.locator(`data-testid=${saveNewViewWithNameID}`).click();
await viewsSaveRequest;
await viewsGetRequest;
const viewName = await page.getByText('Playwright').isVisible();
await expect(viewName).toBeTruthy();
});
});

View File

@ -1,116 +0,0 @@
import { Page } from '@playwright/test';
import attributeKeyDurationNanoSuccessResponse from '../fixtures/api/traces/attributeKeysDurationNano200.json';
import attributeKeyHttpMethodSuccessResponse from '../fixtures/api/traces/attributeKeysHttpMethod200.json';
import attributeKeyNameSuccessResponse from '../fixtures/api/traces/attributeKeysName200.json';
import attributeKeyResponseStatusCodeSuccessResponse from '../fixtures/api/traces/attributeKeysResponseStatusCode200.json';
import attributeKeyServiceNameSuccessResponse from '../fixtures/api/traces/attributeKeysServiceName200.json';
import traceExplorerViewsPostSuccessResponse from '../fixtures/api/traces/traceExplorerViewPost200.json';
import traceExplorerViewsSuccessResponse from '../fixtures/api/traces/traceExplorerViews200.json';
import { JsonApplicationType } from '../fixtures/constant';
export const queryRangeApiEndpoint = 'query_range';
export const attributeKeysApiEndpoint = 'autocomplete/attribute_keys';
export const traceExplorerViewsGetEndpoint = 'explorer/views?sourcePage=traces';
export const traceExplorerViewsPostEndpoint = 'explorer/views';
export const newExplorerCtaID = 'newExplorerCTA';
export const serviceAttributeID = 'serviceName';
export const httpMethodAttributeID = 'httpMethod';
export const traceTabID = 'rc-tabs-0-tab-trace';
export const traceRowTraceTabID = 'trace-id';
export const tableViewTabID = 'rc-tabs-0-tab-table';
export const saveNewViewID = 'traces-save-view-action';
export const saveNewViewWithNameID = 'save-view-name-action-button';
const DefaultAttributesExplorerPage = [
'serviceName',
'name',
'durationNano',
'httpMethod',
'responseStatusCode',
];
export const tracesExplorerQueryData = async (
page: Page,
response: any,
): Promise<void> => {
await page.route(`**/${queryRangeApiEndpoint}`, (route) =>
route.fulfill({
status: 200,
contentType: JsonApplicationType,
json: response,
}),
);
};
export const tracesExplorerViewsData = async (page: Page): Promise<void> => {
await page.route(`**/${traceExplorerViewsGetEndpoint}`, (route) =>
route.fulfill({
status: 200,
contentType: JsonApplicationType,
json: traceExplorerViewsSuccessResponse,
}),
);
};
export const tracesExplorerViewsPostData = async (
page: Page,
): Promise<void> => {
await page.route(`**/${traceExplorerViewsPostEndpoint}`, (route) =>
route.fulfill({
status: 200,
contentType: JsonApplicationType,
json: traceExplorerViewsPostSuccessResponse,
}),
);
};
function getAttributeResponseBySearchTerm(
searchTerm: string,
): Record<string, unknown> {
if (searchTerm) {
switch (searchTerm) {
case 'sericeName':
return attributeKeyServiceNameSuccessResponse;
case 'name':
return attributeKeyNameSuccessResponse;
case 'durationNano':
return attributeKeyDurationNanoSuccessResponse;
case 'httpMethod':
return attributeKeyResponseStatusCodeSuccessResponse;
case 'responseStatusCode':
return attributeKeyHttpMethodSuccessResponse;
default:
return {};
}
}
return {};
}
export const getAttributeKeysData = async (
page: Page,
searchTerm: string,
): Promise<void> => {
await page.route(
`**/${attributeKeysApiEndpoint}?**searchText=${searchTerm}**`,
(route) =>
route.fulfill({
status: 200,
json: getAttributeResponseBySearchTerm(searchTerm),
}),
);
};
export const defaultAttributeKeysData = async (page: Page): Promise<void> => {
await Promise.all([
...DefaultAttributesExplorerPage.map((att) =>
getAttributeKeysData(page, att),
),
]);
};

View File

@ -42,8 +42,6 @@
"./__mocks__",
"./conf/default.conf",
"./public",
"./tests",
"./playwright.config.ts",
"./commitlint.config.ts",
"./webpack.config.js",
"./webpack.config.prod.js",

View File

@ -3170,16 +3170,6 @@
resolved "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.8.0.tgz"
integrity sha512-AhVAm6SQ+zgxIiOzwVdUcDmKlu/qU39FiYD2UD6kQQaVenrn0dGZewIghWAENGQsvC+1avLCuT+T2/3Gsp/W3w==
"@playwright/test@^1.22.0":
version "1.33.0"
resolved "https://registry.npmjs.org/@playwright/test/-/test-1.33.0.tgz"
integrity sha512-YunBa2mE7Hq4CfPkGzQRK916a4tuZoVx/EpLjeWlTVOnD4S2+fdaQZE0LJkbfhN5FTSKNLdcl7MoT5XB37bTkg==
dependencies:
"@types/node" "*"
playwright-core "1.33.0"
optionalDependencies:
fsevents "2.3.2"
"@polka/url@^1.0.0-next.20":
version "1.0.0-next.21"
resolved "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz"
@ -9145,7 +9135,7 @@ fscreen@^1.0.2:
resolved "https://registry.yarnpkg.com/fscreen/-/fscreen-1.2.0.tgz#1a8c88e06bc16a07b473ad96196fb06d6657f59e"
integrity sha512-hlq4+BU0hlPmwsFjwGGzZ+OZ9N/wq9Ljg/sq3pX+2CD7hrJsX9tJgWWK/wiNTFM212CLHWhicOoqwXyZGGetJg==
fsevents@2.3.2, fsevents@^2.3.2, fsevents@~2.3.2:
fsevents@^2.3.2, fsevents@~2.3.2:
version "2.3.2"
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
@ -13839,11 +13829,6 @@ pkg-dir@^7.0.0:
dependencies:
find-up "^6.3.0"
playwright-core@1.33.0:
version "1.33.0"
resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.33.0.tgz"
integrity sha512-aizyPE1Cj62vAECdph1iaMILpT0WUDCq3E6rW6I+dleSbBoGbktvJtzS6VHkZ4DKNEOG9qJpiom/ZxO+S15LAw==
pngquant-bin@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/pngquant-bin/-/pngquant-bin-6.0.1.tgz#2b5789ca219eeb4d8509ab1ae082092801b7f07e"