Skip to content
Merged
35 changes: 32 additions & 3 deletions app/containers/LoginServices/LoginServices.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ServicesSeparator from './ServicesSeparator';
import ButtonService from './ButtonService';
import { type IServices } from '../../selectors/login';
import { type TIconsName } from '../CustomIcon';
import ServiceList from './ServiceList';

const styles = StyleSheet.create({
serviceName: {
Expand Down Expand Up @@ -65,12 +66,12 @@ export default {

export const Separators = () => (
<>
<ServicesSeparator collapsed onPress={() => {}} separator services={services} />
<ServicesSeparator collapsed={false} onPress={() => {}} separator services={services} />
<ServicesSeparator collapsed onPress={() => {}} separator totalServices={4} />
<ServicesSeparator collapsed={false} onPress={() => {}} separator totalServices={4} />
</>
);

export const ServiceList = () => (
export const ServicesList = () => (
<>
{Object.values(services).map(service => {
const icon = `${service.name}-monochromatic` as TIconsName;
Expand All @@ -93,3 +94,31 @@ export const ServiceList = () => (
})}
</>
);

export const ServiceListCollapsed = () => {
return (
<ServiceList
services={services}
CAS_enabled={false}
CAS_login_url=''
Gitlab_URL=''
server='https://demo.rocket.chat'
collapsed={true}
showLoginOnWebButton={true}
/>
);
};

export const ServiceListUncollapsed = () => {
return (
<ServiceList
services={services}
CAS_enabled={false}
CAS_login_url=''
Gitlab_URL=''
server='https://demo.rocket.chat'
collapsed={false}
showLoginOnWebButton={true}
/>
);
};
140 changes: 140 additions & 0 deletions app/containers/LoginServices/LoginServices.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,144 @@
import { Linking } from 'react-native';
import { fireEvent, render, screen } from '@testing-library/react-native';
import { Provider } from 'react-redux';
import type { ReactNode } from 'react';

import { generateSnapshots } from '../../../.rnstorybook/generateSnapshots';
import * as stories from './LoginServices.stories';
import LoginServices from './index';
import { createMockedStore } from '../../reducers/mockedStore';
import { setLoginServices } from '../../actions/login';
import { selectServerRequest } from '../../actions/server';
import { type IServices } from '../../selectors/login';
import { type IItemService } from './interfaces';

jest.mock('../../lib/services/connect', () => ({}));
Comment thread
yash-rajpal marked this conversation as resolved.

generateSnapshots(stories);

jest.mock('./serviceLogin', () => ({}));

jest.mock('react-native/Libraries/Linking/Linking', () => ({
openURL: jest.fn()
}));

const SERVER = 'https://demo.rocket.chat';

const makeService = (overrides: Partial<IItemService> = {}): IItemService =>
({
_id: 'github',

name: 'github',
service: '',
authType: 'oauth',
buttonColor: '',
buttonLabelColor: '',
clientConfig: { provider: '' },
serverURL: '',
authorizePath: '',
clientId: 'client-123',
scope: '',
...overrides
} as IItemService);

const buildServices = (count: number, extra: Partial<IItemService> = {}): IServices => {
const names = ['github', 'gitlab', 'google', 'facebook', 'linkedin', 'twitter', 'wordpress'] as const;
return Object.fromEntries(
names.slice(0, count).map(name => [name, makeService({ _id: name, name: name as any, ...extra })])
) as unknown as IServices;
};

const Wrapper = ({ children, store }: { children: ReactNode; store: ReturnType<typeof createMockedStore> }) => (
<Provider store={store}>{children}</Provider>
);

describe('LoginServices', () => {
it('does not show expand/collapse button when services <= 3', () => {
const store = createMockedStore();
store.dispatch(setLoginServices(buildServices(2)));
render(
<Wrapper store={store}>
<LoginServices separator />
</Wrapper>
);
expect(screen.queryByText('More options')).toBeNull();
});

it('shows expand/collapse button when separator=true and > 3 services, does not show all services', () => {
const store = createMockedStore();
store.dispatch(setLoginServices(buildServices(5)));
render(
<Wrapper store={store}>
<LoginServices separator />
</Wrapper>
);
expect(screen.queryByText('Continue with Facebook')).toBeNull();
expect(screen.queryByText('Continue with Linkedin')).toBeNull();
expect(screen.getByText('More options')).toBeTruthy();
});

it('uncollapses and shows all services', () => {
const store = createMockedStore();
store.dispatch(setLoginServices(buildServices(5)));
render(
<Wrapper store={store}>
<LoginServices separator />
</Wrapper>
);
expect(screen.queryByText('Continue with Facebook')).toBeNull();
expect(screen.queryByText('Continue with Linkedin')).toBeNull();
expect(screen.getByText('More options')).toBeTruthy();

fireEvent.press(screen.getByText('More options'));

expect(screen.getByText('Continue with Facebook')).toBeTruthy();
expect(screen.getByText('Continue with Linkedin')).toBeTruthy();
});

it('filters out services with hideButtonOnMobile=true and shows Login on web button', () => {
const store = createMockedStore();
const services = {
...buildServices(2),
hidden: makeService({ _id: 'hidden', name: 'facebook' as any, hideButtonOnMobile: true })
} as unknown as IServices;
store.dispatch(setLoginServices(services));
render(
<Wrapper store={store}>
<LoginServices separator />
</Wrapper>
);

expect(screen.queryByText('Continue with Facebook')).toBeNull();
expect(screen.queryByText('More options')).toBeNull();
expect(screen.getByText('Login on web')).toBeTruthy();
});

it('does not show Login_on_web button when no services are hidden', () => {
const store = createMockedStore();
store.dispatch(setLoginServices(buildServices(2)));
render(
<Wrapper store={store}>
<LoginServices separator={false} />
</Wrapper>
);
expect(screen.queryByText('Login on web')).toBeNull();
});

it('opens Login on web URL when button is pressed', () => {
const store = createMockedStore();
const services = {
...buildServices(2),
hidden: makeService({ _id: 'hidden', name: 'facebook' as any, hideButtonOnMobile: true })
} as unknown as IServices;
store.dispatch(setLoginServices(services));
store.dispatch(selectServerRequest(SERVER, '6.0.0'));
render(
<Wrapper store={store}>
<LoginServices separator />
</Wrapper>
);

fireEvent.press(screen.getByText('Login on web'));
expect(Linking.openURL).toHaveBeenCalledWith(`${SERVER}/home?loginClient=mobile`);
});
});
43 changes: 43 additions & 0 deletions app/containers/LoginServices/ServiceList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Linking } from 'react-native';

import Service from './Service';
import Button from '../Button';
import { type IServiceList, type IItemService } from './interfaces';
import I18n from '../../i18n';

const ServiceList = ({
services,
CAS_enabled,
CAS_login_url,
Gitlab_URL,
server,
collapsed,
showLoginOnWebButton
}: IServiceList & { showLoginOnWebButton: boolean }) => (
<>
{showLoginOnWebButton && (
<Button
title={I18n.t('Login_on_web')}
onPress={() => {
Linking.openURL(`${server}/home?loginClient=mobile`);
}}
/>
)}
{Object.values(services).map((service: IItemService, index: number) => {
if (index > 2 && collapsed) return null;

return (
<Service
key={service._id}
CAS_enabled={CAS_enabled}
CAS_login_url={CAS_login_url}
Gitlab_URL={Gitlab_URL}
server={server}
service={service}
/>
);
})}
</>
);

export default ServiceList;
8 changes: 3 additions & 5 deletions app/containers/LoginServices/ServicesSeparator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ import styles from './styles';
import I18n from '../../i18n';
import { type IServicesSeparator } from './interfaces';

const ServicesSeparator = ({ services, separator, collapsed, onPress }: IServicesSeparator) => {
const ServicesSeparator = ({ separator, collapsed, onPress, totalServices }: IServicesSeparator) => {
const { colors } = useTheme();

const { length } = Object.values(services);

if (length > 3 && separator) {
if (totalServices > 3 && separator) {
return (
<>
<Button
Expand All @@ -24,7 +22,7 @@ const ServicesSeparator = ({ services, separator, collapsed, onPress }: IService
</>
);
}
if (length > 0 && separator) {
if (totalServices > 0 && separator) {
return <OrSeparator />;
}
return null;
Expand Down
Loading
Loading