Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STSMACOM-886 provide LinkedUser component #1555

Merged
merged 8 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"env": {
"jest": true
},
"extends": "@folio/eslint-config-stripes",
"parser": "@babel/eslint-parser",
"rules": {
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/ui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ jobs:
if: github.ref_name == github.event.repository.default_branch || github.event_name != 'push' || github.ref_type == 'tag'
secrets: inherit
with:
jest-enabled: false
jest-enabled: true
jest-test-command: yarn run test:jest
bigtest-enabled: true
bigtest-test-command: xvfb-run --server-args="-screen 0 1024x768x24" yarn test $YARN_TEST_OPTIONS --karma.singleRun --karma.browsers ChromeDocker --karma.reporters mocha junit --coverage
sonar-sources: ./lib
Expand Down
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,7 @@ export { default as useCustomFields } from './lib/CustomFields/utils/useCustomFi
export { default as ProfilePicture } from './lib/ProfilePicture';
export { default as useProfilePicture } from './lib/ProfilePicture/utils';

export { default as LinkedUser } from './lib/LinkedUser';

export * from './lib/ColumnManager';
export * from './lib/utils';
10 changes: 10 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const path = require('path');
const config = require('@folio/jest-config-stripes');

module.exports = {
...config,
setupFiles: [
...config.setupFiles,
path.join(__dirname, './tests/jest/setupFiles.js'),
],
};
32 changes: 32 additions & 0 deletions lib/LinkedUser/LinkedUser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import PropTypes from 'prop-types';

import { useStripes } from '@folio/stripes-core';
import { getFullName } from '@folio/stripes-util';
import { TextLink } from '@folio/stripes-components';

/**
* LinkedUser
* Link to a user-details record if permissions allow,
* or return a plaintext name.
*/
const LinkedUser = ({ user, formatter = getFullName }) => {
const stripes = useStripes();

return stripes.hasPerm('ui-users.view') ? (
<TextLink to={`/users/preview/${user.id}?query=${user.username}`}>
{formatter(user)}
</TextLink>
) : (
<>{formatter(user)}</>
);
};

LinkedUser.propTypes = {
user: PropTypes.shape({
id: PropTypes.string,
username: PropTypes.string,
}),
formatter: PropTypes.func,
};

export default LinkedUser;
64 changes: 64 additions & 0 deletions lib/LinkedUser/LinkedUser.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { render, screen } from '@folio/jest-config-stripes/testing-library/react';
import { useStripes } from '@folio/stripes-core';

Check warning on line 2 in lib/LinkedUser/LinkedUser.test.js

View workflow job for this annotation

GitHub Actions / ui / Install and lint / Install and lint

'useStripes' is defined but never used. Allowed unused vars must match /React/u

import LinkedUser from './LinkedUser';

const mockHasPerm = jest.fn();

jest.mock('stripes-config', () => (
{
modules: [],
metadata: {},
}
),
{ virtual: true });

jest.mock('@folio/stripes-core', () => ({
...jest.requireActual('@folio/stripes-core'),
useStripes: () => ({ hasPerm: mockHasPerm }),
}));

const userRecord = {
id: 'id',
username: 'username',
personal: {
firstName: 'first',
lastName: 'last',
middleName: 'middle',
}
};

describe('useLinkedUser', () => {
beforeEach(() => {
mockHasPerm.mockReturnValue(true);
});

afterAll(() => {
jest.clearAllMocks();
});

it('returns a link when permission is present', () => {
mockHasPerm.mockReturnValue(true);

const { container } = render(<LinkedUser user={userRecord} />);
expect(container.querySelector('a')).not.toBeNull();
screen.getByText(userRecord.personal.firstName, { exact: false });
});

it('returns plain text when permission is absent', () => {
mockHasPerm.mockReturnValue(false);

const { container } = render(<LinkedUser user={userRecord} />);
expect(container.querySelector('a')).toBeNull();
screen.getByText(userRecord.personal.firstName, { exact: false });
});

it('uses provided formatter', () => {
mockHasPerm.mockReturnValue(true);
const formatter = (u) => u.username;

const { container } = render(<LinkedUser user={userRecord} formatter={formatter} />);
expect(container.querySelector('a')).not.toBeNull();
screen.getByText(userRecord.username);
});
});
1 change: 1 addition & 0 deletions lib/LinkedUser/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './LinkedUser';
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
"lint": "eslint . && stylelint \"lib/**/*.css\"",
"eslint": "eslint .",
"stylelint": "stylelint \"lib/**/*.css\"",
"test": "stripes test karma",
"test:bigtest": "stripes test karma",
"test:jest": "jest --ci --coverage --colors",
"test": "yarn test:jest && yarn test:bigtest",
"test-dev": "stripes test karma --watch",
"build-mod-descriptor": "stripes mod descriptor --full --strict | jq '.[]' > module-descriptor.json ",
"formatjs-compile": "formatjs compile-folder --ast --format simple ./translations/stripes-smart-components ./translations/stripes-smart-components/compiled"
Expand All @@ -44,6 +46,7 @@
"@bigtest/mirage": "^0.0.1",
"@bigtest/mocha": "^0.5.1",
"@folio/eslint-config-stripes": "^7.0.0",
"@folio/jest-config-stripes": "^2.1.0",
"@folio/stripes-cli": "^3.2.1",
"@folio/stripes-components": "^12.0.0",
"@folio/stripes-connect": "^9.0.0",
Expand Down Expand Up @@ -95,10 +98,10 @@
"react-final-form": "^6.3.0",
"react-final-form-arrays": "^3.1.1",
"react-final-form-listeners": "^1.0.3",
"react-image": "^4.1.0",
"react-query": "^3.9.8",
"react-quill": "^2.0.0",
"react-router-prop-types": "^1.0.4",
"react-image": "^4.1.0",
"redux-form": "^8.3.0",
"uuid": "^9.0.0"
},
Expand Down
2 changes: 1 addition & 1 deletion tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ requireTest.keys().forEach(requireTest);
turnOffWarnings();

// require all source files in lib for code coverage
const componentsContext = require.context('../lib/', true, /^(?!.*(stories|examples)).*\.js$/);
const componentsContext = require.context('../lib/', true, /^(?!.*(stories|examples|\.test\.)).*\.js$/);
componentsContext.keys().forEach(componentsContext);
6 changes: 6 additions & 0 deletions tests/jest/__mock__/__resizeObserver.mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
window.ResizeObserver = jest.fn().mockImplementation(() => ({
disconnect: jest.fn(),
observe: jest.fn(),
unobserve: jest.fn(),
}));

1 change: 1 addition & 0 deletions tests/jest/__mock__/currencyData.mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
jest.mock('currency-codes/data', () => ({ filter: () => [] }));
8 changes: 8 additions & 0 deletions tests/jest/__mock__/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import './stripesConfig.mock';
import './stripesCore.mock';
import './stripes.mock';
import './intl.mock';
import './stripesIcon.mock';
import './stripesComponents.mock';
import './currencyData.mock';
import './resizeObserver.mock';
61 changes: 61 additions & 0 deletions tests/jest/__mock__/intl.mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from 'react';

jest.mock('react-intl', () => {
const intl = {
formatMessage: ({ id }) => id,
formatNumber: (value) => value,
formatTime: (value) => value,
formatDisplayName: (value) => value,
formatDate: (value) => value,
formatDateToParts: jest.fn(() => ([
{
'type': 'month',
'value': '7'
},
{
'type': 'literal',
'value': '/'
},
{
'type': 'day',
'value': '31'
},
{
'type': 'literal',
'value': '/'
},
{
'type': 'year',
'value': '2024'
}
]
)),
};

return {
...jest.requireActual('react-intl'),
FormattedMessage: jest.fn(({ id, children }) => {
if (children) {
return children([id]);
}

return id;
}),
FormattedTime: jest.fn(({ value, children }) => {
if (children) {
return children([value]);
}

return value;
}),
FormattedDate: jest.fn(({ value, children }) => {
if (children) {
return children([value]);
}

return value;
}),
useIntl: () => intl,
injectIntl: (Component) => (props) => <Component {...props} intl={intl} />,
};
});
13 changes: 13 additions & 0 deletions tests/jest/__mock__/matchMedia.mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // Deprecated
removeListener: jest.fn(), // Deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
}))
});
9 changes: 9 additions & 0 deletions tests/jest/__mock__/reactFinalFormArrays.mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';

jest.mock('react-final-form-arrays', () => {
return {
...jest.requireActual('react-final-form-arrays'),

FieldArray: () => <div>FieldArray</div>,
};
});
9 changes: 9 additions & 0 deletions tests/jest/__mock__/reactFinalFormListeners.mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';

jest.mock('react-final-form-listeners', () => {
return {
...jest.requireActual('react-final-form-listeners'),

OnChange: jest.fn(({ children }) => <>{children()}</>),
};
});
5 changes: 5 additions & 0 deletions tests/jest/__mock__/resizeObserver.mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
global.ResizeObserver = jest.fn().mockImplementation(() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
}));
26 changes: 26 additions & 0 deletions tests/jest/__mock__/stripes.mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { noop } from 'lodash';

const buildStripes = (otherProperties = {}) => ({
hasPerm: noop,
hasInterface: noop,
clone: noop,
logger: { log: noop },
config: {},
okapi: {
url: '',
tenant: '',
},
locale: 'en-US',
withOkapi: true,
setToken: noop,
actionNames: [],
setLocale: noop,
setTimezone: noop,
setCurrency: noop,
setSinglePlugin: noop,
setBindings: noop,
connect: noop,
...otherProperties,
});

export default buildStripes;
Loading
Loading