Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
martinlagler committed Mar 13, 2024
1 parent 627346e commit ab28ad2
Show file tree
Hide file tree
Showing 25 changed files with 717 additions and 101 deletions.
6 changes: 0 additions & 6 deletions config/routes/sulu_admin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,3 @@ sulu_audience_targeting_api:
type: rest
resource: "@SuluAudienceTargetingBundle/Resources/config/routing_api.yml"
prefix: /admin/api

sulu_admin_single_sign_on:
path: /openid
controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction
defaults:
route: sulu_admin
6 changes: 2 additions & 4 deletions src/Sulu/Bundle/AdminBundle/Controller/AdminController.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types=1);

/*
* This file is part of Sulu.
*
Expand Down Expand Up @@ -252,7 +250,7 @@ public function indexAction()
'translations' => $this->urlGenerator->generate('sulu_admin.translation'),
'generateUrl' => $this->urlGenerator->generate('sulu_page.post_resourcelocator', ['action' => 'generate']),
'routing' => $this->urlGenerator->generate('fos_js_routing_js'),
'single_sign_on' => $this->hasSingleSignOnProvider,
'has_single_sign_on' => $this->hasSingleSignOnProvider,
];

try {
Expand All @@ -271,7 +269,7 @@ public function indexAction()
'password_info_translation_key' => $this->passwordInfoTranslationKey,
'sulu_version' => $this->suluVersion,
'app_version' => $this->appVersion,
'single_sign_on' => $this->hasSingleSignOnProvider,
'has_single_sign_on' => $this->hasSingleSignOnProvider,
]
));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ const LOADER_SIZE = 20;
export default class Input<T: ?string | ?number> extends React.PureComponent<InputProps<T>> {
static defaultProps = {
alignment: 'left',
autoFocus: false,
collapsed: false,
disabled: false,
skin: 'default',
type: 'text',
valid: true,
autoFocus: false,
};

setInputRef = (ref: ?ElementRef<'input'>) => {
Expand Down Expand Up @@ -58,6 +58,7 @@ export default class Input<T: ?string | ?number> extends React.PureComponent<Inp
const {
alignment,
autocomplete,
autoFocus,
headline,
id,
inputClass,
Expand Down Expand Up @@ -87,7 +88,6 @@ export default class Input<T: ?string | ?number> extends React.PureComponent<Inp
min,
max,
step,
autoFocus,
} = this.props;

const inputContainerClass = classNames(
Expand Down Expand Up @@ -146,6 +146,7 @@ export default class Input<T: ?string | ?number> extends React.PureComponent<Inp

<input
autoComplete={autocomplete}
autoFocus={autoFocus}
className={inputClass}
disabled={disabled}
id={id}
Expand All @@ -161,7 +162,6 @@ export default class Input<T: ?string | ?number> extends React.PureComponent<Inp
ref={inputRef ? this.setInputRef : undefined}
step={step}
type={type}
autoFocus={autoFocus}
value={value == null ? '' : value}
/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ test('Input should render', () => {
expect(container).toMatchSnapshot();
});

test('Input should render with autoFocus', () => {
const onChange = jest.fn();
const {container} = render(<Input autoFocus={true} onBlur={jest.fn()} onChange={onChange} value="My value" />);
expect(container).toMatchSnapshot();
});

test('Input should render with autocomplete off', () => {
const onChange = jest.fn();
const {container} = render(<Input autocomplete="off" disabled={true} onChange={onChange} value="My value" />);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,19 @@ exports[`Input should render with a segment counter 1`] = `
</div>
`;

exports[`Input should render with autoFocus 1`] = `
<div>
<div
class="input default left"
>
<input
type="text"
value="My value"
/>
</div>
</div>
`;

exports[`Input should render with autocomplete off 1`] = `
<div>
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {ElementRef} from 'react';
export type InputProps<T: ?string | ?number> = {|
alignment?: 'left' | 'center' | 'right',
autocomplete?: string,
autoFocus?: boolean,
collapsed?: boolean,
disabled: boolean,
headline?: boolean,
Expand Down
25 changes: 21 additions & 4 deletions src/Sulu/Bundle/AdminBundle/Resources/js/containers/Login/Login.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow
import React from 'react';
import {action, computed, observable} from 'mobx';
import {action, autorun, computed, observable} from 'mobx';
import {observer} from 'mobx-react';
import Icon from '../../components/Icon/index';
import {translate} from '../../utils/index';
Expand All @@ -25,11 +25,27 @@ type Props = {|

@observer
class Login extends React.Component<Props> {
redirectDisposer: () => void;

static defaultProps = {
backLink: '/',
initialized: false,
};

constructor(props: Props) {
super(props);

this.redirectDisposer = autorun(() => {
if (userStore.redirectUrl !== '') {
window.location.href = userStore.redirectUrl;
}
});
}

componentWillUnmount() {
this.redirectDisposer();
}

@observable visibleForm: FormTypes = this.props.router.attributes.forgotPasswordToken ? 'reset-password' : 'login';

@computed get loginFormVisible(): boolean {
Expand Down Expand Up @@ -70,7 +86,7 @@ class Login extends React.Component<Props> {

handleLoginFormSubmit = (data: LoginFormData) => {
userStore.login(data).then(() => {
if (userStore.hasJsonLogin) {
if (userStore.loginMethod === 'json_login') {
return;
}

Expand Down Expand Up @@ -139,8 +155,9 @@ class Login extends React.Component<Props> {
<LoginForm
error={userStore.loginError}
loading={userStore.loading}
hasSingleSignOn={userStore.hasSingleSignOn()}
hasOnlyPassword={userStore.hasJsonLogin}
mode={userStore.hasSingleSignOn() ? (
userStore.loginMethod === 'json_login' ? 'password_only' : 'username_only'
) : 'username_password'}
onChangeForm={this.handleChangeToForgotPasswordForm}
onSubmit={this.handleLoginFormSubmit}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import type {LoginFormData} from './types';
type Props = {|
error: boolean,
loading: boolean,
hasSingleSignOn: boolean,
hasOnlyPassword: boolean,
mode: string,
onChangeForm: () => void,
onSubmit: (data: LoginFormData) => void,
|};
Expand All @@ -25,8 +24,7 @@ class LoginForm extends React.Component<Props> {
static defaultProps = {
error: false,
loading: false,
hasSingleSignOn: false,
hasOnlyPassword: false,
mode: 'username_password',
};

@observable inputRef: ?ElementRef<*>;
Expand All @@ -35,7 +33,9 @@ class LoginForm extends React.Component<Props> {
@observable password: ?string;

@computed get submitButtonDisabled(): boolean {
return !(this.user && this.password) && !((this.user || this.password) && this.props.hasSingleSignOn);
return !(this.user && this.password)
&& !((this.user || this.password)
&& this.props.mode !== 'username_password');
}

@action setInputRef = (ref: ?ElementRef<*>) => {
Expand All @@ -59,12 +59,12 @@ class LoginForm extends React.Component<Props> {
@action handleSubmit = (event: SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();

if (this.user && this.props.hasSingleSignOn) {
if (this.user && this.props.mode !== 'username_password') {
const {onSubmit} = this.props;

onSubmit({
username: this.user,
password: this.password,
password: this.password ?? '',
});

if (this.user && this.password) {
Expand Down Expand Up @@ -104,13 +104,14 @@ class LoginForm extends React.Component<Props> {
</Header>
<form className={formStyles.form} onSubmit={this.handleSubmit}>
<fieldset>
{(!this.props.hasOnlyPassword) && (
{(this.props.mode !== 'password_only') && (
<label className={inputFieldClass}>
<div className={formStyles.labelText}>
{translate('sulu_admin.username_or_email')}
</div>
<Input
autocomplete="username"
autoFocus={this.props.mode === 'username_only'}
icon="su-user"
inputRef={this.setInputRef}
onChange={this.handleUserChange}
Expand All @@ -119,35 +120,35 @@ class LoginForm extends React.Component<Props> {
/>
</label>
)}
{(!this.props.hasSingleSignOn || (this.props.hasSingleSignOn && this.props.hasOnlyPassword)) && (
{(this.props.mode !== 'username_only') && (
<label className={inputFieldClass}>
<div className={formStyles.labelText}>
{translate('sulu_admin.password')}
</div>
<Input
autocomplete="current-password"
autoFocus={this.props.mode === 'password_only'}
icon="su-lock"
onChange={this.handlePasswordChange}
type="password"
valid={!this.props.error}
value={this.password}
autoFocus={this.props.hasOnlyPassword}
/>
</label>
)}
<div className={formStyles.buttons}>
<Button onClick={this.props.onChangeForm} skin="link">
{translate('sulu_admin.forgot_password')}
</Button>
<Button
disabled={this.submitButtonDisabled}
loading={this.props.loading}
skin="primary"
type="submit"
>
{translate('sulu_admin.login')}
</Button>
</div>
<div className={formStyles.buttons}>
<Button onClick={this.props.onChangeForm} skin="link">
{translate('sulu_admin.forgot_password')}
</Button>
<Button
disabled={this.submitButtonDisabled}
loading={this.props.loading}
skin="primary"
type="submit"
>
{translate('sulu_admin.login')}
</Button>
</div>
</fieldset>
</form>
</Fragment>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ const mockUserStoreTwoFactorError = jest.fn();
const mockUserStoreSetResetSuccess = jest.fn();
const mockUserStoreLoading = jest.fn().mockReturnValue(false);
const mockUserStoreForgotPasswordSuccess = jest.fn().mockReturnValue(false);
const mockUserStoreHasJsonLogin = jest.fn().mockReturnValue(false);
const mockUserStoreHasSingleSignOn = jest.fn().mockReturnValue(false);
const mockUserStoreLoginMethod = jest.fn().mockReturnValue(false);
const mockUserStoreHasSingleSignOn = jest.fn();
const mockUserStoreRedirectUrl = jest.fn().mockReturnValue('');

jest.mock('../../../stores/userStore', () => {
return new class {
Expand Down Expand Up @@ -68,12 +69,16 @@ jest.mock('../../../stores/userStore', () => {
return mockUserStoreSetResetSuccess(value);
}

get loginMethod() {
return mockUserStoreLoginMethod();
}

hasSingleSignOn() {
return mockUserStoreHasSingleSignOn();
}

get hasJsonLogin() {
return mockUserStoreHasJsonLogin();
redirectUrl() {
return mockUserStoreRedirectUrl();
}

get loading() {
Expand Down Expand Up @@ -260,22 +265,24 @@ test('Should not call the submit handler of the reset password view with not mat

test('Should render the Login with only username/email', () => {
const router = new Router();
mockUserStoreHasSingleSignOn.mockReturnValueOnce(true);
mockUserStoreHasSingleSignOn.mockReturnValue(true);
mockUserStoreLoginMethod.mockReturnValueOnce('');

const loginForm = mount(
<Login initialized={true} onLoginSuccess={jest.fn()} router={router} />
);

expect(loginForm.render()).toMatchSnapshot()
expect(loginForm.render()).toMatchSnapshot();
});

test('Should render the Login with only password', () => {
const router = new Router();
mockUserStoreHasJsonLogin.mockReturnValue(true);
mockUserStoreHasSingleSignOn.mockReturnValue(true);
mockUserStoreLoginMethod.mockReturnValue('json_login');

const loginForm = mount(
<Login initialized={true} onLoginSuccess={jest.fn()} router={router} />
);

expect(loginForm.render()).toMatchSnapshot()
expect(loginForm.render()).toMatchSnapshot();
});
Loading

0 comments on commit ab28ad2

Please sign in to comment.