mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-07-20 03:04:25 +08:00
Added unit test case for billing and workspaceLock compnent. (#3781)
This commit is contained in:
parent
f12abfbe01
commit
e12cf3e494
@ -154,6 +154,7 @@
|
||||
"@types/react-resizable": "3.0.3",
|
||||
"@types/react-router-dom": "^5.1.6",
|
||||
"@types/react-syntax-highlighter": "15.5.7",
|
||||
"@types/redux-mock-store": "1.0.4",
|
||||
"@types/styled-components": "^5.1.4",
|
||||
"@types/uuid": "^8.3.1",
|
||||
"@types/webpack": "^5.28.0",
|
||||
@ -192,6 +193,7 @@
|
||||
"react-hooks-testing-library": "0.6.0",
|
||||
"react-hot-loader": "^4.13.0",
|
||||
"react-resizable": "3.0.4",
|
||||
"redux-mock-store": "1.5.4",
|
||||
"sass": "1.66.1",
|
||||
"sass-loader": "13.3.2",
|
||||
"ts-jest": "^27.1.5",
|
||||
|
@ -0,0 +1,195 @@
|
||||
import { billingSuccessResponse } from 'mocks-server/__mockdata__/billing';
|
||||
import {
|
||||
notOfTrailResponse,
|
||||
trialConvertedToSubscriptionResponse,
|
||||
} from 'mocks-server/__mockdata__/licenses';
|
||||
import { server } from 'mocks-server/server';
|
||||
import { rest } from 'msw';
|
||||
import { act, render, screen } from 'tests/test-utils';
|
||||
import { getFormattedDate } from 'utils/timeUtils';
|
||||
|
||||
import BillingContainer from './BillingContainer';
|
||||
|
||||
const lisenceUrl = 'http://localhost/api/v2/licenses';
|
||||
|
||||
describe('BillingContainer', () => {
|
||||
test('Component should render', async () => {
|
||||
act(() => {
|
||||
render(<BillingContainer />);
|
||||
});
|
||||
const unit = screen.getAllByText(/unit/i);
|
||||
expect(unit[1]).toBeInTheDocument();
|
||||
const dataInjection = screen.getByRole('columnheader', {
|
||||
name: /data ingested/i,
|
||||
});
|
||||
expect(dataInjection).toBeInTheDocument();
|
||||
const pricePerUnit = screen.getByRole('columnheader', {
|
||||
name: /price per unit/i,
|
||||
});
|
||||
expect(pricePerUnit).toBeInTheDocument();
|
||||
const cost = screen.getByRole('columnheader', {
|
||||
name: /cost \(billing period to date\)/i,
|
||||
});
|
||||
expect(cost).toBeInTheDocument();
|
||||
|
||||
const total = screen.getByRole('cell', {
|
||||
name: /total/i,
|
||||
});
|
||||
expect(total).toBeInTheDocument();
|
||||
|
||||
const manageBilling = screen.getByRole('button', {
|
||||
name: /manage billing/i,
|
||||
});
|
||||
expect(manageBilling).toBeInTheDocument();
|
||||
|
||||
const dollar = screen.getByRole('cell', {
|
||||
name: /\$0/i,
|
||||
});
|
||||
expect(dollar).toBeInTheDocument();
|
||||
|
||||
const currentBill = screen.getByRole('heading', {
|
||||
name: /current bill total/i,
|
||||
});
|
||||
expect(currentBill).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('OnTrail', async () => {
|
||||
act(() => {
|
||||
render(<BillingContainer />);
|
||||
});
|
||||
|
||||
const freeTrailText = await screen.findByText('Free Trial');
|
||||
expect(freeTrailText).toBeInTheDocument();
|
||||
|
||||
const currentBill = await screen.findByRole('heading', {
|
||||
name: /current bill total/i,
|
||||
});
|
||||
expect(currentBill).toBeInTheDocument();
|
||||
|
||||
const dollar0 = await screen.findByText(/\$0/i);
|
||||
expect(dollar0).toBeInTheDocument();
|
||||
const onTrail = await screen.findByText(
|
||||
/You are in free trial period. Your free trial will end on 20 Oct 2023/i,
|
||||
);
|
||||
expect(onTrail).toBeInTheDocument();
|
||||
|
||||
const numberOfDayRemaining = await screen.findByText(
|
||||
/1 days remaining in your billing period./i,
|
||||
);
|
||||
expect(numberOfDayRemaining).toBeInTheDocument();
|
||||
const upgradeButton = await screen.findAllByRole('button', {
|
||||
name: /upgrade/i,
|
||||
});
|
||||
expect(upgradeButton[1]).toBeInTheDocument();
|
||||
expect(upgradeButton.length).toBe(2);
|
||||
const checkPaidPlan = await screen.findByText(
|
||||
/Check out features in paid plans/i,
|
||||
);
|
||||
expect(checkPaidPlan).toBeInTheDocument();
|
||||
|
||||
const link = screen.getByRole('link', { name: /here/i });
|
||||
expect(link).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('OnTrail but trialConvertedToSubscription', async () => {
|
||||
server.use(
|
||||
rest.get(lisenceUrl, (req, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(trialConvertedToSubscriptionResponse)),
|
||||
),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
render(<BillingContainer />);
|
||||
});
|
||||
|
||||
const currentBill = await screen.findByRole('heading', {
|
||||
name: /current bill total/i,
|
||||
});
|
||||
expect(currentBill).toBeInTheDocument();
|
||||
|
||||
const dollar0 = await screen.findByText(/\$0/i);
|
||||
expect(dollar0).toBeInTheDocument();
|
||||
|
||||
const onTrail = await screen.findByText(
|
||||
/You are in free trial period. Your free trial will end on 20 Oct 2023/i,
|
||||
);
|
||||
expect(onTrail).toBeInTheDocument();
|
||||
|
||||
const receivedCardDetails = await screen.findByText(
|
||||
/We have received your card details, your billing will only start after the end of your free trial period./i,
|
||||
);
|
||||
expect(receivedCardDetails).toBeInTheDocument();
|
||||
|
||||
const manageBillingButton = await screen.findByRole('button', {
|
||||
name: /manage billing/i,
|
||||
});
|
||||
expect(manageBillingButton).toBeInTheDocument();
|
||||
|
||||
const dayRemainingInBillingPeriod = await screen.findByText(
|
||||
/1 days remaining in your billing period./i,
|
||||
);
|
||||
expect(dayRemainingInBillingPeriod).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Not on ontrail', async () => {
|
||||
server.use(
|
||||
rest.get(lisenceUrl, (req, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(notOfTrailResponse)),
|
||||
),
|
||||
);
|
||||
render(<BillingContainer />);
|
||||
|
||||
const billingPeriodText = `Your current billing period is from ${getFormattedDate(
|
||||
billingSuccessResponse.data.billingPeriodStart,
|
||||
)} to ${getFormattedDate(billingSuccessResponse.data.billingPeriodEnd)}`;
|
||||
|
||||
const billingPeriod = await screen.findByRole('heading', {
|
||||
name: new RegExp(billingPeriodText, 'i'),
|
||||
});
|
||||
expect(billingPeriod).toBeInTheDocument();
|
||||
|
||||
const currentBill = await screen.findByRole('heading', {
|
||||
name: /current bill total/i,
|
||||
});
|
||||
expect(currentBill).toBeInTheDocument();
|
||||
|
||||
const dollar0 = await screen.findAllByText(/\$1278.3/i);
|
||||
expect(dollar0[0]).toBeInTheDocument();
|
||||
expect(dollar0.length).toBe(2);
|
||||
|
||||
const metricsRow = await screen.findByRole('row', {
|
||||
name: /metrics Million 4012 0.1 \$ 401.2/i,
|
||||
});
|
||||
expect(metricsRow).toBeInTheDocument();
|
||||
|
||||
const logRow = await screen.findByRole('row', {
|
||||
name: /Logs GB 497 0.4 \$ 198.8/i,
|
||||
});
|
||||
expect(logRow).toBeInTheDocument();
|
||||
|
||||
const totalBill = await screen.findByRole('cell', {
|
||||
name: /\$1278/i,
|
||||
});
|
||||
expect(totalBill).toBeInTheDocument();
|
||||
|
||||
const totalBillRow = await screen.findByRole('row', {
|
||||
name: /total \$1278/i,
|
||||
});
|
||||
expect(totalBillRow).toBeInTheDocument();
|
||||
|
||||
screen.debug();
|
||||
});
|
||||
|
||||
test('Should render corrent day remaining in billing period', async () => {
|
||||
server.use(
|
||||
rest.get(lisenceUrl, (req, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(notOfTrailResponse)),
|
||||
),
|
||||
);
|
||||
render(<BillingContainer />);
|
||||
const dayRemainingInBillingPeriod = await screen.findByText(
|
||||
/11 days remaining in your billing period./i,
|
||||
);
|
||||
expect(dayRemainingInBillingPeriod).toBeInTheDocument();
|
||||
});
|
||||
});
|
54
frontend/src/mocks-server/__mockdata__/billing.ts
Normal file
54
frontend/src/mocks-server/__mockdata__/billing.ts
Normal file
@ -0,0 +1,54 @@
|
||||
export const billingSuccessResponse = {
|
||||
status: 'success',
|
||||
data: {
|
||||
billingPeriodStart: 1697197809,
|
||||
billingPeriodEnd: 1698777000,
|
||||
details: {
|
||||
total: 1278.3,
|
||||
breakdown: [
|
||||
{
|
||||
type: 'Metrics',
|
||||
unit: 'Million',
|
||||
tiers: [
|
||||
{
|
||||
unitPrice: 0.1,
|
||||
quantity: 4012,
|
||||
tierStart: 0,
|
||||
tierEnd: 0,
|
||||
tierCost: 401.2,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'Traces',
|
||||
unit: 'GB',
|
||||
tiers: [
|
||||
{
|
||||
unitPrice: 0.3,
|
||||
quantity: 2261,
|
||||
tierStart: 0,
|
||||
tierEnd: 0,
|
||||
tierCost: 678.3,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'Logs',
|
||||
unit: 'GB',
|
||||
tiers: [
|
||||
{
|
||||
unitPrice: 0.4,
|
||||
quantity: 497,
|
||||
tierStart: 0,
|
||||
tierEnd: 0,
|
||||
tierCost: 198.8,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
baseFee: 199,
|
||||
billTotal: 1278.3,
|
||||
},
|
||||
discount: 0,
|
||||
},
|
||||
};
|
90
frontend/src/mocks-server/__mockdata__/licenses.ts
Normal file
90
frontend/src/mocks-server/__mockdata__/licenses.ts
Normal file
@ -0,0 +1,90 @@
|
||||
export const licensesSuccessResponse = {
|
||||
status: 'success',
|
||||
data: {
|
||||
trialStart: 1695992049,
|
||||
trialEnd: 1697806449,
|
||||
onTrial: true,
|
||||
workSpaceBlock: false,
|
||||
trialConvertedToSubscription: false,
|
||||
gracePeriodEnd: -1,
|
||||
licenses: [
|
||||
{
|
||||
key: 'testKeyId1',
|
||||
activationId: 'testActivationId1',
|
||||
ValidationMessage: '',
|
||||
isCurrent: false,
|
||||
planKey: 'ENTERPRISE_PLAN',
|
||||
ValidFrom: '2022-10-13T13:48:51Z',
|
||||
ValidUntil: '2023-10-13T19:37:37Z',
|
||||
status: 'VALID',
|
||||
},
|
||||
{
|
||||
key: 'testKeyId2',
|
||||
activationId: 'testActivationId2',
|
||||
ValidationMessage: '',
|
||||
isCurrent: true,
|
||||
planKey: 'ENTERPRISE_PLAN',
|
||||
ValidFrom: '2023-09-12T11:35:43Z',
|
||||
ValidUntil: '2024-09-11T17:24:29Z',
|
||||
status: 'VALID',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const trialConvertedToSubscriptionResponse = {
|
||||
status: 'success',
|
||||
data: {
|
||||
trialStart: 1695992049,
|
||||
trialEnd: 1697806449,
|
||||
onTrial: true,
|
||||
workSpaceBlock: false,
|
||||
trialConvertedToSubscription: true,
|
||||
gracePeriodEnd: -1,
|
||||
licenses: [
|
||||
{
|
||||
key: 'testKeyId1',
|
||||
activationId: 'testActivationId1',
|
||||
ValidationMessage: '',
|
||||
isCurrent: false,
|
||||
planKey: 'ENTERPRISE_PLAN',
|
||||
ValidFrom: '2022-10-13T13:48:51Z',
|
||||
ValidUntil: '2023-10-13T19:37:37Z',
|
||||
status: 'VALID',
|
||||
},
|
||||
{
|
||||
key: 'testKeyId2',
|
||||
activationId: 'testActivationId2',
|
||||
ValidationMessage: '',
|
||||
isCurrent: true,
|
||||
planKey: 'ENTERPRISE_PLAN',
|
||||
ValidFrom: '2023-09-12T11:35:43Z',
|
||||
ValidUntil: '2024-09-11T17:24:29Z',
|
||||
status: 'VALID',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const notOfTrailResponse = {
|
||||
...trialConvertedToSubscriptionResponse,
|
||||
data: {
|
||||
...trialConvertedToSubscriptionResponse.data,
|
||||
onTrial: false,
|
||||
trialConvertedToSubscriptionResponse: false,
|
||||
trialStart: -1,
|
||||
trialEnd: -1,
|
||||
},
|
||||
};
|
||||
|
||||
export const workSpaceBlockResponse = {
|
||||
...trialConvertedToSubscriptionResponse,
|
||||
data: {
|
||||
...trialConvertedToSubscriptionResponse.data,
|
||||
onTrial: false,
|
||||
trialConvertedToSubscriptionResponse: false,
|
||||
trialStart: -1,
|
||||
trialEnd: -1,
|
||||
workSpaceBlock: true,
|
||||
},
|
||||
};
|
@ -1,5 +1,7 @@
|
||||
import { rest } from 'msw';
|
||||
|
||||
import { billingSuccessResponse } from './__mockdata__/billing';
|
||||
import { licensesSuccessResponse } from './__mockdata__/licenses';
|
||||
import { queryRangeSuccessResponse } from './__mockdata__/query_range';
|
||||
import { serviceSuccessResponse } from './__mockdata__/services';
|
||||
import { topLevelOperationSuccessResponse } from './__mockdata__/top_level_operations';
|
||||
@ -70,4 +72,13 @@ export const handlers = [
|
||||
return res(ctx.status(500));
|
||||
},
|
||||
),
|
||||
|
||||
rest.get('http://localhost/api/v2/licenses', (req, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(licensesSuccessResponse)),
|
||||
),
|
||||
|
||||
// ?licenseKey=58707e3d-3bdb-44e7-8c89-a9be237939f4
|
||||
rest.get('http://localhost/api/v1/billing', (req, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(billingSuccessResponse)),
|
||||
),
|
||||
];
|
||||
|
48
frontend/src/pages/WorkspaceLocked/WorkspaceLocked.test.tsx
Normal file
48
frontend/src/pages/WorkspaceLocked/WorkspaceLocked.test.tsx
Normal file
@ -0,0 +1,48 @@
|
||||
import { act, render, screen } from 'tests/test-utils';
|
||||
|
||||
import WorkspaceLocked from '.';
|
||||
|
||||
describe('WorkspaceLocked', () => {
|
||||
test('Should render the component', async () => {
|
||||
act(() => {
|
||||
render(<WorkspaceLocked />);
|
||||
});
|
||||
const workspaceLocked = screen.getByRole('heading', {
|
||||
name: /workspace locked/i,
|
||||
});
|
||||
expect(workspaceLocked).toBeInTheDocument();
|
||||
|
||||
const gotQuestionText = screen.getByText(/got question?/i);
|
||||
expect(gotQuestionText).toBeInTheDocument();
|
||||
|
||||
const contactUsLink = screen.getByRole('link', {
|
||||
name: /contact us/i,
|
||||
});
|
||||
expect(contactUsLink).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Render for Admin', async () => {
|
||||
render(<WorkspaceLocked />);
|
||||
const contactAdminMessage = screen.queryByText(
|
||||
/please contact your administrator for further help/i,
|
||||
);
|
||||
expect(contactAdminMessage).not.toBeInTheDocument();
|
||||
const updateCreditCardBtn = screen.getByRole('button', {
|
||||
name: /update credit card/i,
|
||||
});
|
||||
expect(updateCreditCardBtn).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Render for non Admin', async () => {
|
||||
render(<WorkspaceLocked />, {}, 'VIEWER');
|
||||
const updateCreditCardBtn = screen.queryByRole('button', {
|
||||
name: /update credit card/i,
|
||||
});
|
||||
expect(updateCreditCardBtn).not.toBeInTheDocument();
|
||||
|
||||
const contactAdminMessage = screen.getByText(
|
||||
/please contact your administrator for further help/i,
|
||||
);
|
||||
expect(contactAdminMessage).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -5,6 +5,7 @@ import React, { ReactElement } from 'react';
|
||||
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||
import { Provider } from 'react-redux';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import configureStore from 'redux-mock-store';
|
||||
import store from 'store';
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
@ -19,6 +20,25 @@ afterEach(() => {
|
||||
queryClient.clear();
|
||||
});
|
||||
|
||||
const mockStore = configureStore([]);
|
||||
|
||||
const mockStored = (role?: string): any =>
|
||||
mockStore({
|
||||
...store.getState(),
|
||||
app: {
|
||||
...store.getState().app,
|
||||
role, // Use the role provided
|
||||
user: {
|
||||
userId: '6f532456-8cc0-4514-a93b-aed665c32b47',
|
||||
email: 'test@signoz.io',
|
||||
name: 'TestUser',
|
||||
profilePictureURL: '',
|
||||
accessJwt: '',
|
||||
refreshJwt: '',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
jest.mock('react-i18next', () => ({
|
||||
useTranslation: (): {
|
||||
t: (str: string) => string;
|
||||
@ -42,13 +62,17 @@ jest.mock('react-router-dom', () => ({
|
||||
|
||||
function AllTheProviders({
|
||||
children,
|
||||
role, // Accept the role as a prop
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
role: string; // Define the role prop
|
||||
}): ReactElement {
|
||||
return (
|
||||
<ResourceProvider>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Provider store={store}>
|
||||
<Provider store={mockStored(role)}>
|
||||
{' '}
|
||||
{/* Use the mock store with the provided role */}
|
||||
<BrowserRouter>{children}</BrowserRouter>
|
||||
</Provider>
|
||||
</QueryClientProvider>
|
||||
@ -59,7 +83,12 @@ function AllTheProviders({
|
||||
const customRender = (
|
||||
ui: ReactElement,
|
||||
options?: Omit<RenderOptions, 'wrapper'>,
|
||||
): RenderResult => render(ui, { wrapper: AllTheProviders, ...options });
|
||||
role = 'ADMIN', // Set a default role
|
||||
): RenderResult =>
|
||||
render(ui, {
|
||||
wrapper: () => <AllTheProviders role={role}>{ui}</AllTheProviders>,
|
||||
...options,
|
||||
});
|
||||
|
||||
export * from '@testing-library/react';
|
||||
export { customRender as render };
|
||||
|
@ -3573,6 +3573,13 @@
|
||||
"@types/scheduler" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/redux-mock-store@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/redux-mock-store/-/redux-mock-store-1.0.4.tgz#d82d97d61314f02a3849a18edabd1a169581e632"
|
||||
integrity sha512-53nDnXba4M7aOJsRod8HKENDC9M2ccm19yZcXImoP15oDLuBru+Q+WKWOCQwKYOC1S/6AJx58mFp8kd4s8q1rQ==
|
||||
dependencies:
|
||||
redux "^4.0.5"
|
||||
|
||||
"@types/retry@0.12.0":
|
||||
version "0.12.0"
|
||||
resolved "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz"
|
||||
@ -9992,6 +9999,11 @@ lodash.isequal@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
||||
integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
|
||||
|
||||
lodash.isplainobject@^4.0.6:
|
||||
version "4.0.6"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
|
||||
integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==
|
||||
|
||||
lodash.memoize@4.x, lodash.memoize@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz"
|
||||
@ -13009,6 +13021,13 @@ redent@^3.0.0:
|
||||
indent-string "^4.0.0"
|
||||
strip-indent "^3.0.0"
|
||||
|
||||
redux-mock-store@1.5.4:
|
||||
version "1.5.4"
|
||||
resolved "https://registry.yarnpkg.com/redux-mock-store/-/redux-mock-store-1.5.4.tgz#90d02495fd918ddbaa96b83aef626287c9ab5872"
|
||||
integrity sha512-xmcA0O/tjCLXhh9Fuiq6pMrJCwFRaouA8436zcikdIpYWWCjU76CRk+i2bHx8EeiSiMGnB85/lZdU3wIJVXHTA==
|
||||
dependencies:
|
||||
lodash.isplainobject "^4.0.6"
|
||||
|
||||
redux-thunk@^2.3.0:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz"
|
||||
|
Loading…
x
Reference in New Issue
Block a user