test(user-interface-configuration): write initial tests (#1242)
* test(user-interface): add tests with playwright * test: refactor UI configuration tests --------- Co-authored-by: Ali BARIN <ali.barin53@gmail.com>
This commit is contained in:
@@ -42,6 +42,7 @@ function createDrawerLinks({
|
||||
Icon: GroupIcon,
|
||||
primary: 'adminSettingsDrawer.users',
|
||||
to: URLS.USERS,
|
||||
dataTest: 'users-drawer-link',
|
||||
}
|
||||
: null,
|
||||
canReadRole
|
||||
@@ -49,6 +50,7 @@ function createDrawerLinks({
|
||||
Icon: GroupsIcon,
|
||||
primary: 'adminSettingsDrawer.roles',
|
||||
to: URLS.ROLES,
|
||||
dataTest: 'roles-drawer-link',
|
||||
}
|
||||
: null,
|
||||
canUpdateConfig
|
||||
@@ -56,6 +58,7 @@ function createDrawerLinks({
|
||||
Icon: BrushIcon,
|
||||
primary: 'adminSettingsDrawer.userInterface',
|
||||
to: URLS.USER_INTERFACE,
|
||||
dataTest: 'user-interface-drawer-link',
|
||||
}
|
||||
: null,
|
||||
canManageSamlAuthProvider
|
||||
@@ -63,6 +66,7 @@ function createDrawerLinks({
|
||||
Icon: LockIcon,
|
||||
primary: 'adminSettingsDrawer.authentication',
|
||||
to: URLS.AUTHENTICATION,
|
||||
dataTest: 'authentication-drawer-link',
|
||||
}
|
||||
: null,
|
||||
].filter(Boolean) as DrawerLink[];
|
||||
@@ -75,6 +79,7 @@ const drawerBottomLinks = [
|
||||
Icon: ArrowBackIosNewIcon,
|
||||
primary: 'adminSettingsDrawer.goBack',
|
||||
to: '/',
|
||||
dataTest: 'go-back-drawer-link',
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -46,7 +46,7 @@ export default function AppBar(props: AppBarProps): React.ReactElement {
|
||||
};
|
||||
|
||||
return (
|
||||
<MuiAppBar>
|
||||
<MuiAppBar data-test="app-bar">
|
||||
<Container maxWidth={maxWidth} disableGutters>
|
||||
<Toolbar>
|
||||
<IconButton
|
||||
|
40
packages/web/src/components/ColorInput/ColorButton/index.tsx
Normal file
40
packages/web/src/components/ColorInput/ColorButton/index.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
import { ButtonProps } from '@mui/material/Button';
|
||||
import { Button } from './style';
|
||||
|
||||
const BG_IMAGE_FALLBACK =
|
||||
'linear-gradient(45deg, #ccc 25%, transparent 25%), linear-gradient(135deg, #ccc 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #ccc 75%), linear-gradient(135deg, transparent 75%, #ccc 75%) /*! @noflip */';
|
||||
|
||||
export type ColorButtonProps = Omit<ButtonProps, 'children'> & {
|
||||
bgColor: string;
|
||||
isBgColorValid: boolean;
|
||||
disablePopover: boolean;
|
||||
};
|
||||
|
||||
export type ColorButtonElement = (props: ColorButtonProps) => JSX.Element;
|
||||
|
||||
const ColorButton = (props: ColorButtonProps) => {
|
||||
const {
|
||||
bgColor,
|
||||
className,
|
||||
disablePopover,
|
||||
isBgColorValid,
|
||||
...restButtonProps
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Button
|
||||
data-test="color-button"
|
||||
disableTouchRipple
|
||||
style={{
|
||||
backgroundColor: isBgColorValid ? bgColor : undefined,
|
||||
backgroundImage: isBgColorValid ? undefined : BG_IMAGE_FALLBACK,
|
||||
cursor: disablePopover ? 'default' : undefined,
|
||||
}}
|
||||
className={`MuiColorInput-Button ${className || ''}`}
|
||||
{...restButtonProps}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColorButton;
|
15
packages/web/src/components/ColorInput/ColorButton/style.tsx
Normal file
15
packages/web/src/components/ColorInput/ColorButton/style.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import MuiButton from '@mui/material/Button';
|
||||
import { styled } from '@mui/material/styles';
|
||||
|
||||
export const Button = styled(MuiButton)(() => ({
|
||||
backgroundSize: '8px 8px',
|
||||
backgroundPosition: '0 0, 4px 0, 4px -4px, 0px 4px',
|
||||
transition: 'none',
|
||||
boxShadow: '0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08)',
|
||||
border: 0,
|
||||
borderRadius: 4,
|
||||
width: '24px',
|
||||
aspectRatio: '1 / 1',
|
||||
height: '24px',
|
||||
minWidth: 0,
|
||||
})) as typeof MuiButton;
|
@@ -1,6 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
import { MuiColorInput, MuiColorInputProps } from 'mui-color-input';
|
||||
import ColorButton from './ColorButton';
|
||||
|
||||
type ColorInputProps = {
|
||||
shouldUnregister?: boolean;
|
||||
@@ -15,7 +16,6 @@ export default function ColorInput(props: ColorInputProps): React.ReactElement {
|
||||
name,
|
||||
shouldUnregister = false,
|
||||
disabled = false,
|
||||
'data-test': dataTest,
|
||||
...textFieldProps
|
||||
} = props;
|
||||
|
||||
@@ -27,12 +27,13 @@ export default function ColorInput(props: ColorInputProps): React.ReactElement {
|
||||
shouldUnregister={shouldUnregister}
|
||||
render={({ field }) => (
|
||||
<MuiColorInput
|
||||
Adornment={ColorButton}
|
||||
format="hex"
|
||||
{...textFieldProps}
|
||||
{...field}
|
||||
disabled={disabled}
|
||||
inputProps={{
|
||||
'data-test': dataTest,
|
||||
'data-test': 'color-text-field',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
@@ -8,7 +8,10 @@ const CustomLogo = () => {
|
||||
const logoSvgData = config['logo.svgData'] as string;
|
||||
|
||||
return (
|
||||
<img src={`data:image/svg+xml;utf8,${encodeURIComponent(logoSvgData)}`} />
|
||||
<img
|
||||
data-test="custom-logo"
|
||||
src={`data:image/svg+xml;utf8,${encodeURIComponent(logoSvgData)}`}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
@@ -68,19 +68,22 @@ export default function Drawer(props: DrawerProps): React.ReactElement {
|
||||
</div>
|
||||
|
||||
<List sx={{ py: 0, mt: 3 }}>
|
||||
{bottomLinks.map(({ Icon, badgeContent, primary, to }, index) => (
|
||||
<ListItemLink
|
||||
key={`${to}-${index}`}
|
||||
icon={
|
||||
<Badge badgeContent={badgeContent} color="secondary" max={99}>
|
||||
<Icon htmlColor={theme.palette.primary.main} />
|
||||
</Badge>
|
||||
}
|
||||
primary={formatMessage(primary)}
|
||||
to={to}
|
||||
onClick={closeOnClick}
|
||||
/>
|
||||
))}
|
||||
{bottomLinks.map(
|
||||
({ Icon, badgeContent, primary, to, dataTest }, index) => (
|
||||
<ListItemLink
|
||||
key={`${to}-${index}`}
|
||||
icon={
|
||||
<Badge badgeContent={badgeContent} color="secondary" max={99}>
|
||||
<Icon htmlColor={theme.palette.primary.main} />
|
||||
</Badge>
|
||||
}
|
||||
primary={formatMessage(primary)}
|
||||
to={to}
|
||||
onClick={closeOnClick}
|
||||
data-test={dataTest}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</List>
|
||||
</BaseDrawer>
|
||||
);
|
||||
|
@@ -18,7 +18,7 @@ type FlowRowProps = {
|
||||
flow: IFlow;
|
||||
};
|
||||
|
||||
function getFlowStatusTranslationKey(status: IFlow["status"]): string {
|
||||
function getFlowStatusTranslationKey(status: IFlow['status']): string {
|
||||
if (status === 'published') {
|
||||
return 'flow.published';
|
||||
} else if (status === 'paused') {
|
||||
@@ -28,7 +28,16 @@ function getFlowStatusTranslationKey(status: IFlow["status"]): string {
|
||||
return 'flow.draft';
|
||||
}
|
||||
|
||||
function getFlowStatusColor(status: IFlow["status"]): 'default' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' {
|
||||
function getFlowStatusColor(
|
||||
status: IFlow['status']
|
||||
):
|
||||
| 'default'
|
||||
| 'primary'
|
||||
| 'secondary'
|
||||
| 'error'
|
||||
| 'info'
|
||||
| 'success'
|
||||
| 'warning' {
|
||||
if (status === 'published') {
|
||||
return 'success';
|
||||
} else if (status === 'paused') {
|
||||
@@ -64,8 +73,12 @@ export default function FlowRow(props: FlowRowProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card sx={{ mb: 1 }}>
|
||||
<CardActionArea component={Link} to={URLS.FLOW(flow.id)}>
|
||||
<Card sx={{ mb: 1 }} data-test="flow-row">
|
||||
<CardActionArea
|
||||
component={Link}
|
||||
to={URLS.FLOW(flow.id)}
|
||||
data-test="card-action-area"
|
||||
>
|
||||
<CardContent>
|
||||
<Apps direction="row" gap={1} sx={{ gridArea: 'apps' }}>
|
||||
<FlowAppIcons steps={flow.steps} />
|
||||
@@ -98,9 +111,7 @@ export default function FlowRow(props: FlowRowProps): React.ReactElement {
|
||||
size="small"
|
||||
color={getFlowStatusColor(flow?.status)}
|
||||
variant={flow?.active ? 'filled' : 'outlined'}
|
||||
label={formatMessage(
|
||||
getFlowStatusTranslationKey(flow?.status)
|
||||
)}
|
||||
label={formatMessage(getFlowStatusTranslationKey(flow?.status))}
|
||||
/>
|
||||
|
||||
<IconButton
|
||||
|
@@ -9,12 +9,12 @@ const Logo = () => {
|
||||
const { config, loading } = useConfig(['logo.svgData']);
|
||||
|
||||
const logoSvgData = config?.['logo.svgData'] as string;
|
||||
if (loading && !logoSvgData) return (<React.Fragment />);
|
||||
if (loading && !logoSvgData) return <React.Fragment />;
|
||||
|
||||
if (logoSvgData) return <CustomLogo />;
|
||||
|
||||
return (
|
||||
<Typography variant="h6" component="h1" noWrap>
|
||||
<Typography variant="h6" component="h1" data-test="typography-logo" noWrap>
|
||||
<FormattedMessage id="brandText" />
|
||||
</Typography>
|
||||
);
|
||||
|
@@ -90,18 +90,21 @@ export default function UserInterface(): React.ReactElement {
|
||||
name="palette.primary.main"
|
||||
label={formatMessage('userInterfacePage.mainColor')}
|
||||
fullWidth
|
||||
data-test="primary-main-color-input"
|
||||
/>
|
||||
|
||||
<ColorInput
|
||||
name="palette.primary.dark"
|
||||
label={formatMessage('userInterfacePage.darkColor')}
|
||||
fullWidth
|
||||
data-test="primary-dark-color-input"
|
||||
/>
|
||||
|
||||
<ColorInput
|
||||
name="palette.primary.light"
|
||||
label={formatMessage('userInterfacePage.lightColor')}
|
||||
fullWidth
|
||||
data-test="primary-light-color-input"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
@@ -109,6 +112,7 @@ export default function UserInterface(): React.ReactElement {
|
||||
label={formatMessage('userInterfacePage.svgData')}
|
||||
multiline
|
||||
fullWidth
|
||||
data-test="logo-svg-data-text-field"
|
||||
/>
|
||||
|
||||
<LoadingButton
|
||||
@@ -117,6 +121,7 @@ export default function UserInterface(): React.ReactElement {
|
||||
color="primary"
|
||||
sx={{ boxShadow: 2 }}
|
||||
loading={loading}
|
||||
data-test="update-button"
|
||||
>
|
||||
{formatMessage('userInterfacePage.submit')}
|
||||
</LoadingButton>
|
||||
|
Reference in New Issue
Block a user