mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
Add E2E test environment variables and update E2E tests
This commit is contained in:
@@ -69,6 +69,7 @@ const LoginPage: () => JSX.Element = () => {
|
||||
title: 'Email',
|
||||
fieldType: FormFieldSchemaType.Email,
|
||||
required: true,
|
||||
dataTestId: 'email',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
@@ -85,6 +86,7 @@ const LoginPage: () => JSX.Element = () => {
|
||||
url: new Route('/accounts/forgot-password'),
|
||||
openLinkInNewTab: false,
|
||||
},
|
||||
dataTestId: 'password',
|
||||
},
|
||||
]}
|
||||
createOrUpdateApiUrl={apiUrl}
|
||||
|
||||
@@ -104,6 +104,7 @@ const RegisterPage: () => JSX.Element = () => {
|
||||
required: true,
|
||||
disabled: Boolean(initialValues && initialValues['email']),
|
||||
title: 'Email',
|
||||
dataTestId: 'email',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
@@ -113,6 +114,7 @@ const RegisterPage: () => JSX.Element = () => {
|
||||
placeholder: 'Jeff Smith',
|
||||
required: true,
|
||||
title: 'Full Name',
|
||||
dataTestId: 'name',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -126,6 +128,7 @@ const RegisterPage: () => JSX.Element = () => {
|
||||
placeholder: 'Acme, Inc.',
|
||||
required: true,
|
||||
title: 'Company Name',
|
||||
dataTestId: 'companyName',
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -139,6 +142,7 @@ const RegisterPage: () => JSX.Element = () => {
|
||||
required: true,
|
||||
placeholder: '+11234567890',
|
||||
title: 'Phone Number',
|
||||
dataTestId: 'companyPhoneNumber',
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -155,6 +159,7 @@ const RegisterPage: () => JSX.Element = () => {
|
||||
placeholder: 'Password',
|
||||
title: 'Password',
|
||||
required: true,
|
||||
dataTestId: 'password',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
@@ -170,6 +175,7 @@ const RegisterPage: () => JSX.Element = () => {
|
||||
overrideFieldKey: 'confirmPassword',
|
||||
required: true,
|
||||
showEvenIfPermissionDoesNotExist: true,
|
||||
dataTestId: 'confirmPassword',
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface CategoryProps {
|
||||
onChange: (value: Array<CategoryCheckboxValue>) => void;
|
||||
initialValue?: undefined | Array<CategoryCheckboxValue>;
|
||||
isLastCategory: boolean;
|
||||
dataTestId?: string | undefined;
|
||||
}
|
||||
|
||||
enum CategoryCheckboxValueState {
|
||||
@@ -67,6 +68,7 @@ const Category: FunctionComponent<CategoryProps> = (
|
||||
<div>
|
||||
<CheckboxElement
|
||||
title={props.category.title}
|
||||
dataTestId={props.dataTestId}
|
||||
value={
|
||||
categoryCheckboxState ===
|
||||
CategoryCheckboxValueState.Checked
|
||||
|
||||
@@ -18,6 +18,7 @@ export interface CategoryCheckboxProps
|
||||
onChange: (value: Array<CategoryCheckboxValue>) => void;
|
||||
initialValue?: undefined | Array<CategoryCheckboxValue | BaseModel>;
|
||||
error?: string | undefined;
|
||||
dataTestId?: string | undefined;
|
||||
}
|
||||
|
||||
const CategoryCheckbox: FunctionComponent<CategoryCheckboxProps> = (
|
||||
@@ -112,6 +113,7 @@ const CategoryCheckbox: FunctionComponent<CategoryCheckboxProps> = (
|
||||
return Boolean(option);
|
||||
}
|
||||
)}
|
||||
dataTestId={props.dataTestId}
|
||||
category={category}
|
||||
options={options.filter((option: CategoryCheckboxOption) => {
|
||||
return (option.categoryId || '') === (category?.id || '');
|
||||
|
||||
@@ -19,7 +19,7 @@ export interface ComponentProps {
|
||||
type: CodeType;
|
||||
onFocus?: (() => void) | undefined;
|
||||
onBlur?: (() => void) | undefined;
|
||||
dataTestId?: string;
|
||||
dataTestId?: string | undefined;
|
||||
tabIndex?: number | undefined;
|
||||
error?: string | undefined;
|
||||
value?: string | undefined;
|
||||
|
||||
@@ -31,6 +31,7 @@ export interface ComponentProps {
|
||||
tabIndex?: number | undefined;
|
||||
error?: string | undefined;
|
||||
id?: string | undefined;
|
||||
dataTestId?: string | undefined;
|
||||
}
|
||||
|
||||
const Dropdown: FunctionComponent<ComponentProps> = (
|
||||
@@ -144,6 +145,7 @@ const Dropdown: FunctionComponent<ComponentProps> = (
|
||||
onBlur={() => {
|
||||
props.onBlur && props.onBlur();
|
||||
}}
|
||||
data-testid={props.dataTestId}
|
||||
tabIndex={props.tabIndex}
|
||||
isMulti={props.isMultiSelect}
|
||||
value={value || null}
|
||||
|
||||
@@ -28,7 +28,7 @@ export interface ComponentProps {
|
||||
mimeTypes?: Array<MimeType> | undefined;
|
||||
onFocus?: (() => void) | undefined;
|
||||
onBlur?: (() => void) | undefined;
|
||||
dataTestId?: string;
|
||||
dataTestId?: string | undefined;
|
||||
isMultiFilePicker?: boolean | undefined;
|
||||
tabIndex?: number | undefined;
|
||||
error?: string | undefined;
|
||||
|
||||
@@ -258,6 +258,7 @@ const FormField: <T extends GenericObject>(
|
||||
? props.error
|
||||
: undefined
|
||||
}
|
||||
dataTestId={props.field.dataTestId}
|
||||
onChange={async (value: Color | null) => {
|
||||
props.field.onChange &&
|
||||
props.field.onChange(value);
|
||||
@@ -288,6 +289,7 @@ const FormField: <T extends GenericObject>(
|
||||
}
|
||||
id={props.field.id}
|
||||
tabIndex={index}
|
||||
dataTestId={props.field.dataTestId}
|
||||
onChange={async (
|
||||
value:
|
||||
| DropdownValue
|
||||
@@ -321,13 +323,13 @@ const FormField: <T extends GenericObject>(
|
||||
{props.field.fieldType === FormFieldSchemaType.ObjectID && (
|
||||
<IDGenerator
|
||||
tabIndex={index}
|
||||
dataTestId={props.field.dataTestId}
|
||||
disabled={props.isDisabled || props.field.disabled}
|
||||
error={
|
||||
props.touched && props.error
|
||||
? props.error
|
||||
: undefined
|
||||
}
|
||||
dataTestId={fieldType}
|
||||
onChange={(value: ObjectID) => {
|
||||
props.field.onChange &&
|
||||
props.field.onChange(value);
|
||||
@@ -355,6 +357,7 @@ const FormField: <T extends GenericObject>(
|
||||
? props.error
|
||||
: undefined
|
||||
}
|
||||
dataTestId={props.field.dataTestId}
|
||||
onChange={async (value: string) => {
|
||||
props.field.onChange &&
|
||||
props.field.onChange(value);
|
||||
@@ -381,6 +384,7 @@ const FormField: <T extends GenericObject>(
|
||||
: undefined
|
||||
}
|
||||
tabIndex={index}
|
||||
dataTestId={props.field.dataTestId}
|
||||
onChange={async (value: string) => {
|
||||
props.field.onChange &&
|
||||
props.field.onChange(value);
|
||||
@@ -410,6 +414,7 @@ const FormField: <T extends GenericObject>(
|
||||
}
|
||||
type={CodeType.JSON}
|
||||
tabIndex={index}
|
||||
dataTestId={props.field.dataTestId}
|
||||
onChange={async (value: string) => {
|
||||
props.field.onChange &&
|
||||
props.field.onChange(value);
|
||||
@@ -445,6 +450,7 @@ const FormField: <T extends GenericObject>(
|
||||
? props.error
|
||||
: undefined
|
||||
}
|
||||
dataTestId={props.field.dataTestId}
|
||||
tabIndex={index}
|
||||
type={CodeType.Markdown}
|
||||
onChange={async (value: string) => {
|
||||
@@ -515,6 +521,7 @@ const FormField: <T extends GenericObject>(
|
||||
onBlur={async () => {
|
||||
props.setFieldTouched(props.fieldName, true);
|
||||
}}
|
||||
dataTestId={props.field.dataTestId}
|
||||
type={codeType}
|
||||
initialValue={
|
||||
props.currentValues &&
|
||||
@@ -583,6 +590,7 @@ const FormField: <T extends GenericObject>(
|
||||
]
|
||||
: []
|
||||
}
|
||||
dataTestId={props.field.dataTestId}
|
||||
initialValue={
|
||||
props.currentValues &&
|
||||
(props.currentValues as any)[props.fieldName]
|
||||
@@ -610,6 +618,7 @@ const FormField: <T extends GenericObject>(
|
||||
onBlur={async () => {
|
||||
props.setFieldTouched(props.fieldName, true);
|
||||
}}
|
||||
dataTestId={props.field.dataTestId}
|
||||
initialValue={
|
||||
props.currentValues &&
|
||||
(props.currentValues as any)[props.fieldName] &&
|
||||
@@ -641,6 +650,7 @@ const FormField: <T extends GenericObject>(
|
||||
props.field.onChange(value);
|
||||
props.setFieldValue(props.fieldName, value);
|
||||
}}
|
||||
dataTestId={props.field.dataTestId}
|
||||
onBlur={async () => {
|
||||
props.setFieldTouched(props.fieldName, true);
|
||||
}}
|
||||
@@ -679,6 +689,7 @@ const FormField: <T extends GenericObject>(
|
||||
? props.error
|
||||
: undefined
|
||||
}
|
||||
dataTestId={props.field.dataTestId}
|
||||
onChange={async (
|
||||
value: Array<CategoryCheckboxValue>
|
||||
) => {
|
||||
@@ -727,7 +738,7 @@ const FormField: <T extends GenericObject>(
|
||||
? props.error
|
||||
: undefined
|
||||
}
|
||||
dataTestId={fieldType}
|
||||
dataTestId={props.field.dataTestId}
|
||||
type={fieldType as InputType}
|
||||
onChange={(value: string) => {
|
||||
props.field.onChange &&
|
||||
|
||||
@@ -90,4 +90,5 @@ export default interface Field<TEntity> {
|
||||
props: CustomElementProps
|
||||
) => ReactElement | undefined; // custom element to render instead of the elements in the form.
|
||||
categoryCheckboxProps?: CategoryCheckboxProps | undefined; // props for the category checkbox component. If fieldType is CategoryCheckbox, this prop is required.
|
||||
dataTestId?: string | undefined;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ export interface RadioButton {
|
||||
value: string;
|
||||
sideTitle?: string | undefined;
|
||||
sideDescription?: string | undefined;
|
||||
|
||||
}
|
||||
|
||||
export interface ComponentProps {
|
||||
@@ -19,6 +20,7 @@ export interface ComponentProps {
|
||||
initialValue?: string | undefined;
|
||||
options: Array<RadioButton>;
|
||||
error?: string | undefined;
|
||||
dataTestId?: string | undefined;
|
||||
}
|
||||
|
||||
const RadioButtons: FunctionComponent<ComponentProps> = (
|
||||
@@ -45,7 +47,7 @@ const RadioButtons: FunctionComponent<ComponentProps> = (
|
||||
|
||||
return (
|
||||
<div>
|
||||
<fieldset role="radiogroup">
|
||||
<fieldset role="radiogroup" data-testid={props.dataTestId}>
|
||||
<div className="space-y-2 mt-2">
|
||||
{props.options &&
|
||||
props.options.map(
|
||||
|
||||
@@ -18,6 +18,7 @@ export interface ComponentProps {
|
||||
tabIndex?: number | undefined;
|
||||
error?: string | undefined;
|
||||
autoFocus?: boolean | undefined;
|
||||
dataTestId?: string | undefined;
|
||||
}
|
||||
|
||||
const TextArea: FunctionComponent<ComponentProps> = (
|
||||
@@ -58,6 +59,7 @@ const TextArea: FunctionComponent<ComponentProps> = (
|
||||
<textarea
|
||||
autoFocus={props.autoFocus}
|
||||
placeholder={props.placeholder}
|
||||
data-testid={props.dataTestId}
|
||||
className={`${className || ''}`}
|
||||
value={text}
|
||||
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface ComponentProps {
|
||||
title?: string | undefined;
|
||||
description?: string | undefined;
|
||||
error?: string | undefined;
|
||||
dataTestId?: string | undefined;
|
||||
}
|
||||
|
||||
const Toggle: FunctionComponent<ComponentProps> = (
|
||||
@@ -76,6 +77,7 @@ const Toggle: FunctionComponent<ComponentProps> = (
|
||||
props.onFocus();
|
||||
}
|
||||
}}
|
||||
data-testid={props.dataTestId}
|
||||
onBlur={() => {
|
||||
if (props.onBlur) {
|
||||
props.onBlur();
|
||||
|
||||
@@ -35,6 +35,7 @@ const Welcome: FunctionComponent<ComponentProps> = (
|
||||
onClick={() => {
|
||||
props.onClickShowProjectModal();
|
||||
}}
|
||||
dataTestId='create-new-project-button'
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -13,3 +13,8 @@ export const HTTP_PROTOCOL: Protocol =
|
||||
env('HTTP_PROTOCOL') === 'https' ? Protocol.HTTPS : Protocol.HTTP;
|
||||
|
||||
export const BASE_URL: URL = URL.fromString(`${HTTP_PROTOCOL}${HOST}`);
|
||||
|
||||
export const IS_USER_REGISTERED: boolean = env('E2E_TEST_IS_USER_REGISTERED') === 'true';
|
||||
export const REGISTERED_USER_EMAIL: string = env('E2E_TEST_REGISTERED_USER_EMAIL') || '';
|
||||
export const REGISTERED_USER_PASSWORD: string = env('E2E_TEST_REGISTERED_USER_PASSWORD') || '';
|
||||
|
||||
|
||||
0
E2E/Tests/Accounts/Login.spec.ts
Normal file
0
E2E/Tests/Accounts/Login.spec.ts
Normal file
37
E2E/Tests/Accounts/Register.spec.ts
Normal file
37
E2E/Tests/Accounts/Register.spec.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { BASE_URL, IS_USER_REGISTERED } from '../../Config';
|
||||
import Faker from 'Common/Utils/Faker';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
test.describe('Account Registration', () => {
|
||||
test('should register a new account', async ({ page }) => {
|
||||
|
||||
if(IS_USER_REGISTERED) {
|
||||
// pass this test if user is already registered
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
await page.goto(URL.fromString(BASE_URL.toString()).addRoute('/accounts/register').toString());
|
||||
await page.getByTestId('email').click();
|
||||
await page.getByTestId('email').fill(Faker.generateEmail().toString());
|
||||
await page.getByTestId('email').press('Tab');
|
||||
await page.getByTestId('name').fill('sample');
|
||||
await page.getByTestId('name').press('Tab');
|
||||
await page.getByTestId('companyName').fill('sample');
|
||||
await page.getByTestId('companyName').press('Tab');
|
||||
await page.getByTestId('companyPhoneNumber').fill('+15853641376');
|
||||
await page.getByTestId('companyPhoneNumber').press('Tab');
|
||||
await page.getByTestId('password').fill('sample');
|
||||
await page.getByTestId('password').press('Tab');
|
||||
await page.getByTestId('confirmPassword').fill('sample');
|
||||
await page.getByTestId('Sign Up').click();
|
||||
|
||||
// wait for navigation with base url
|
||||
await page.waitForURL(URL.fromString(BASE_URL.toString()).addRoute('/dashboard/welcome').toString());
|
||||
expect(page.url()).toBe(URL.fromString(BASE_URL.toString()).addRoute('/dashboard/welcome').toString());
|
||||
|
||||
await page.getByTestId('create-new-project-button').click();
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
@@ -1,23 +1,24 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { BASE_URL } from '../../Config';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
|
||||
|
||||
test.describe('check live and health check of the app', () => {
|
||||
|
||||
test('check if app status is ok', async ({ page }) => {
|
||||
await page.goto(`${BASE_URL.addRoute("/status").toString()}`);
|
||||
await page.goto(`${URL.fromString(BASE_URL.toString()).addRoute("/status").toString()}`);
|
||||
const content = await page.content();
|
||||
expect(content).toContain('{"status":"ok"}');
|
||||
});
|
||||
|
||||
test('check if app is ready', async ({ page }) => {
|
||||
await page.goto(`${BASE_URL.addRoute("/status/ready").toString()}`);
|
||||
await page.goto(`${URL.fromString(BASE_URL.toString()).addRoute("/status/ready").toString()}`);
|
||||
const content = await page.content();
|
||||
expect(content).toContain('{"status":"ok"}');
|
||||
});
|
||||
|
||||
test('check if app is live', async ({ page }) => {
|
||||
await page.goto(`${BASE_URL.addRoute("/status/live").toString()}`);
|
||||
await page.goto(`${URL.fromString(BASE_URL.toString()).addRoute("/status/live").toString()}`);
|
||||
const content = await page.content();
|
||||
expect(content).toContain('{"status":"ok"}');
|
||||
});
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { test, expect, Page } from '@playwright/test';
|
||||
import { BASE_URL } from '../../Config';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
|
||||
test.beforeEach(async ({ page }: { page: Page }) => {
|
||||
await page.goto(BASE_URL.toString());
|
||||
await page.goto(URL.fromString(BASE_URL.toString()).toString());
|
||||
});
|
||||
test.describe('check if pages loades with its title', () => {
|
||||
test('has title', async ({ page }: { page: Page }) => {
|
||||
@@ -19,6 +20,6 @@ test.describe('check if pages loades with its title', () => {
|
||||
.getByRole('link', { name: 'OneUptime', exact: true })
|
||||
.click();
|
||||
|
||||
await expect(page).toHaveURL(BASE_URL.toString());
|
||||
await expect(page).toHaveURL(URL.fromString(BASE_URL.toString()).toString());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { test, expect, Page } from '@playwright/test';
|
||||
import { BASE_URL } from '../../Config';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
|
||||
test.beforeEach(async ({ page }: { page: Page }) => {
|
||||
await page.goto(BASE_URL.toString());
|
||||
await page.goto(URL.fromString(BASE_URL.toString()).toString());
|
||||
});
|
||||
|
||||
test.describe('navigation bar', () => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { test, expect, Page } from '@playwright/test';
|
||||
import { BASE_URL } from '../../Config';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
test.beforeEach(async ({ page }: { page: Page }) => {
|
||||
await page.goto(BASE_URL.toString());
|
||||
await page.goto(URL.fromString(BASE_URL.toString()).toString());
|
||||
});
|
||||
test('sign in button ', async ({ page }: { page: Page }) => {
|
||||
await page.getByRole('link', { name: 'Sign in' }).click();
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { test, expect, Page } from '@playwright/test';
|
||||
import { BASE_URL } from '../../Config';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
|
||||
test.beforeEach(async ({ page }: { page: Page }) => {
|
||||
await page.goto(BASE_URL.toString());
|
||||
await page.goto(URL.fromString(BASE_URL.toString()).toString());
|
||||
});
|
||||
test('sign up button', async ({ page }: { page: Page }) => {
|
||||
await page.getByTestId('Sign-up').click();
|
||||
await expect(page).toHaveURL(
|
||||
BASE_URL.addRoute('/accounts/register').toString()
|
||||
URL.fromString(BASE_URL.toString()).addRoute('/accounts/register').toString()
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { BASE_URL } from '../../Config';
|
||||
|
||||
import URL from 'Common/Types/API/URL';
|
||||
|
||||
test.describe('check live and health check of the app', () => {
|
||||
|
||||
test('check if app status is ok', async ({ page }) => {
|
||||
await page.goto(`${BASE_URL.addRoute("/ingestor/status").toString()}`);
|
||||
await page.goto(`${URL.fromString(BASE_URL.toString()).addRoute("/ingestor/status").toString()}`);
|
||||
const content = await page.content();
|
||||
expect(content).toContain('{"status":"ok"}');
|
||||
});
|
||||
|
||||
test('check if app is ready', async ({ page }) => {
|
||||
await page.goto(`${BASE_URL.addRoute("/ingestor/status/ready").toString()}`);
|
||||
await page.goto(`${URL.fromString(BASE_URL.toString()).addRoute("/ingestor/status/ready").toString()}`);
|
||||
const content = await page.content();
|
||||
expect(content).toContain('{"status":"ok"}');
|
||||
});
|
||||
|
||||
test('check if app is live', async ({ page }) => {
|
||||
await page.goto(`${BASE_URL.addRoute("/ingestor/status/live").toString()}`);
|
||||
await page.goto(`${URL.fromString(BASE_URL.toString()).addRoute("/ingestor/status/live").toString()}`);
|
||||
const content = await page.content();
|
||||
expect(content).toContain('{"status":"ok"}');
|
||||
});
|
||||
|
||||
@@ -197,4 +197,7 @@ cronJobs:
|
||||
enabled: false
|
||||
e2e:
|
||||
enabled: false
|
||||
isUserRegistered: false
|
||||
registeredUserEmail:
|
||||
registeredUserPassword:
|
||||
|
||||
@@ -193,5 +193,10 @@ ADMIN_DASHBOARD_OPENTELEMETRY_EXPORTER_OTLP_HEADERS=
|
||||
LOG_LEVEL=ERROR
|
||||
|
||||
|
||||
# Thse env vars are for E2E tests
|
||||
E2E_TEST_IS_USER_REGISTERED=false
|
||||
E2E_TEST_USER_EMAIL=
|
||||
E2E_TEST_USER_PASSWORD=
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user